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(
64  "DlMuAckSequenceType",
65  "Type of the acknowledgment sequence for DL MU PPDUs.",
67  MakeEnumAccessor<WifiAcknowledgment::Method>(&WifiDefaultAckManager::m_dlMuAckType),
69  "DL_MU_BAR_BA_SEQUENCE",
71  "DL_MU_TF_MU_BAR",
73  "DL_MU_AGGREGATE_TF"))
74  .AddAttribute("MaxBlockAckMcs",
75  "The MCS used to send a BlockAck in a TB PPDU is the minimum between "
76  "the MCS used for the PSDU sent in the preceding DL MU PPDU and the "
77  "value of this attribute.",
78  UintegerValue(5),
80  MakeUintegerChecker<uint8_t>(0, 11));
81  return tid;
82 }
83 
85 {
86  NS_LOG_FUNCTION(this);
87 }
88 
90 {
92 }
93 
94 uint16_t
96  const WifiTxParameters& txParams) const
97 {
98  NS_LOG_FUNCTION(this << *mpdu << &txParams);
99 
100  auto receiver = mpdu->GetHeader().GetAddr1();
101  auto origReceiver = mpdu->GetOriginal()->GetHeader().GetAddr1();
102 
103  uint8_t tid = mpdu->GetHeader().GetQosTid();
104  Ptr<QosTxop> edca = m_mac->GetQosTxop(tid);
106  "An established Block Ack agreement is required");
107 
108  uint16_t startingSeq = edca->GetBaStartingSequence(origReceiver, tid);
109  uint16_t maxDistFromStartingSeq =
110  (mpdu->GetHeader().GetSequenceNumber() - startingSeq + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE;
111  NS_ABORT_MSG_IF(maxDistFromStartingSeq >= SEQNO_SPACE_HALF_SIZE,
112  "The given QoS data frame is too old");
113 
114  const WifiTxParameters::PsduInfo* psduInfo = txParams.GetPsduInfo(receiver);
115 
116  if (!psduInfo || psduInfo->seqNumbers.find(tid) == psduInfo->seqNumbers.end())
117  {
118  // there are no aggregated MPDUs (so far)
119  return maxDistFromStartingSeq;
120  }
121 
122  for (const auto& seqNumber : psduInfo->seqNumbers.at(tid))
123  {
124  if (!QosUtilsIsOldPacket(startingSeq, seqNumber))
125  {
126  uint16_t currDistToStartingSeq =
127  (seqNumber - startingSeq + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE;
128 
129  if (currDistToStartingSeq > maxDistFromStartingSeq)
130  {
131  maxDistFromStartingSeq = currDistToStartingSeq;
132  }
133  }
134  }
135 
136  NS_LOG_DEBUG("Returning " << maxDistFromStartingSeq);
137  return maxDistFromStartingSeq;
138 }
139 
140 bool
142  const WifiTxParameters& txParams) const
143 {
144  NS_LOG_FUNCTION(this << *mpdu << &txParams);
145 
146  uint8_t tid = mpdu->GetHeader().GetQosTid();
147  Mac48Address receiver = mpdu->GetOriginal()->GetHeader().GetAddr1();
148  Ptr<QosTxop> edca = m_mac->GetQosTxop(tid);
149 
150  // An immediate response (Ack or Block Ack) is needed if any of the following holds:
151  // * the maximum distance between the sequence number of an MPDU to transmit
152  // and the starting sequence number of the transmit window is greater than
153  // or equal to the window size multiplied by the BaThreshold
154  // * no other frame belonging to this BA agreement is queued (because, in such
155  // a case, a Block Ack is not going to be requested anytime soon)
156  // * this is the initial frame of a transmission opportunity and it is not
157  // protected by RTS/CTS (see Annex G.3 of IEEE 802.11-2016)
158  return !(
159  m_baThreshold > 0 &&
160  GetMaxDistFromStartingSeq(mpdu, txParams) <
161  m_baThreshold * edca->GetBaBufferSize(receiver, tid) &&
162  (edca->GetWifiMacQueue()->GetNPackets({WIFI_QOSDATA_QUEUE, WIFI_UNICAST, receiver, tid}) -
163  edca->GetBaManager()->GetNBufferedPackets(receiver, tid) >
164  1) &&
166  edca->GetRemainingTxop(m_linkId) == edca->GetTxopLimit(m_linkId) &&
167  !(txParams.m_protection && txParams.m_protection->method == WifiProtection::RTS_CTS)));
168 }
169 
170 bool
172 {
173  NS_ASSERT(mpdu->GetHeader().IsQosData());
174  auto tid = mpdu->GetHeader().GetQosTid();
175  NS_ASSERT(mpdu->IsQueued());
176  auto queue = m_mac->GetTxopQueue(mpdu->GetQueueAc());
177  auto origReceiver = mpdu->GetOriginal()->GetHeader().GetAddr1();
178  auto agreement = m_mac->GetBaAgreementEstablishedAsOriginator(origReceiver, tid);
179  NS_ASSERT(agreement);
180  auto mpduDist = agreement->get().GetDistance(mpdu->GetHeader().GetSequenceNumber());
181 
182  Ptr<WifiMpdu> item = queue->PeekByTidAndAddress(tid, origReceiver);
183 
184  while (item)
185  {
186  auto itemDist = agreement->get().GetDistance(item->GetHeader().GetSequenceNumber());
187  if (itemDist == mpduDist)
188  {
189  NS_LOG_DEBUG("No previous MPDU in-flight on the same link");
190  return false;
191  }
192  NS_ABORT_MSG_IF(itemDist > mpduDist,
193  "While searching for given MPDU ("
194  << *mpdu << "), found first another one (" << *item
195  << ") with higher sequence number");
196  if (auto linkIds = item->GetInFlightLinkIds(); linkIds.count(m_linkId) > 0)
197  {
198  NS_LOG_DEBUG("Found MPDU inflight on the same link");
199  return true;
200  }
201  item = queue->PeekByTidAndAddress(tid, origReceiver, item);
202  }
203  NS_ABORT_MSG("Should not get here");
204  return false;
205 }
206 
207 std::unique_ptr<WifiAcknowledgment>
209 {
210  NS_LOG_FUNCTION(this << *mpdu << &txParams);
211 
212  // If the TXVECTOR indicates a DL MU PPDU, call a separate method
213  if (txParams.m_txVector.IsDlMu())
214  {
215  switch (m_dlMuAckType)
216  {
218  return GetAckInfoIfBarBaSequence(mpdu, txParams);
220  return GetAckInfoIfTfMuBar(mpdu, txParams);
222  return GetAckInfoIfAggregatedMuBar(mpdu, txParams);
223  default:
224  NS_ABORT_MSG("Unknown DL acknowledgment method");
225  return nullptr;
226  }
227  }
228 
229  const WifiMacHeader& hdr = mpdu->GetHeader();
230  Mac48Address receiver = hdr.GetAddr1();
231 
232  // Acknowledgment for TB PPDUs
233  if (txParams.m_txVector.IsUlMu())
234  {
235  if (hdr.IsQosData() && !hdr.HasData())
236  {
237  // QoS Null frame
238  std::unique_ptr<WifiAcknowledgment> acknowledgment;
239 
240  if (txParams.m_acknowledgment)
241  {
243  acknowledgment = txParams.m_acknowledgment->Copy();
244  }
245  else
246  {
247  acknowledgment = std::make_unique<WifiNoAck>();
248  }
249  acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::NO_ACK);
250  return acknowledgment;
251  }
252 
253  if (txParams.m_acknowledgment)
254  {
256  return nullptr;
257  }
258 
259  auto acknowledgment = std::make_unique<WifiAckAfterTbPpdu>();
260  if (hdr.IsQosData())
261  {
262  acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::NORMAL_ACK);
263  }
264  return acknowledgment;
265  }
266 
267  // if this is a Trigger Frame, call a separate method
268  if (hdr.IsTrigger())
269  {
270  return TryUlMuTransmission(mpdu, txParams);
271  }
272 
273  // if the current acknowledgment method (if any) is already BLOCK_ACK, it will not
274  // change by adding an MPDU
275  if (txParams.m_acknowledgment &&
277  {
278  return nullptr;
279  }
280 
281  if (receiver.IsGroup())
282  {
283  NS_ABORT_MSG_IF(txParams.GetSize(receiver) > 0, "Unicast frames only can be aggregated");
284  auto acknowledgment = std::make_unique<WifiNoAck>();
285  if (hdr.IsQosData())
286  {
287  acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::NO_ACK);
288  }
289  return acknowledgment;
290  }
291 
292  if ((!hdr.IsQosData() ||
294  !hdr.IsBlockAckReq())
295  {
296  NS_LOG_DEBUG(
297  "Non-QoS data frame or Block Ack agreement not established, request Normal Ack");
298  auto acknowledgment = std::make_unique<WifiNormalAck>();
299  acknowledgment->ackTxVector =
300  GetWifiRemoteStationManager()->GetAckTxVector(receiver, txParams.m_txVector);
301  if (hdr.IsQosData())
302  {
303  acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::NORMAL_ACK);
304  }
305  return acknowledgment;
306  }
307 
308  // we get here if mpdu is a QoS data frame related to an established Block Ack agreement
309  // or mpdu is a BlockAckReq frame
310  if (!hdr.IsBlockAckReq() && !IsResponseNeeded(mpdu, txParams))
311  {
312  NS_LOG_DEBUG("A response is not needed: no ack for now, use Block Ack policy");
313  if (txParams.m_acknowledgment &&
314  txParams.m_acknowledgment->method == WifiAcknowledgment::NONE)
315  {
316  // no change if the ack method is already NONE
317  return nullptr;
318  }
319 
320  auto acknowledgment = std::make_unique<WifiNoAck>();
321  if (hdr.IsQosData())
322  {
323  acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::BLOCK_ACK);
324  }
325  return acknowledgment;
326  }
327 
328  // we get here if a response is needed
329  uint8_t tid = GetTid(mpdu->GetPacket(), hdr);
330  if (!hdr.IsBlockAckReq() && txParams.GetSize(receiver) == 0 && !ExistInflightOnSameLink(mpdu))
331  {
332  NS_LOG_DEBUG("Sending a single MPDU, no previous frame to ack: request Normal Ack");
333  auto acknowledgment = std::make_unique<WifiNormalAck>();
334  acknowledgment->ackTxVector =
335  GetWifiRemoteStationManager()->GetAckTxVector(receiver, txParams.m_txVector);
336  acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::NORMAL_ACK);
337  return acknowledgment;
338  }
339 
340  // we get here if multiple MPDUs are being/have been sent
341  if (!hdr.IsBlockAckReq() && (txParams.GetSize(receiver) == 0 || m_useExplicitBar))
342  {
343  // in case of single MPDU, there are previous unacknowledged frames, thus
344  // we cannot use Implicit Block Ack Request policy, otherwise we get a
345  // normal ack as response
346  NS_LOG_DEBUG("Request to schedule a Block Ack Request");
347 
348  auto acknowledgment = std::make_unique<WifiBarBlockAck>();
349  acknowledgment->blockAckReqTxVector =
350  GetWifiRemoteStationManager()->GetBlockAckTxVector(receiver, txParams.m_txVector);
351  acknowledgment->blockAckTxVector = acknowledgment->blockAckReqTxVector;
352  acknowledgment->barType = m_mac->GetBarTypeAsOriginator(receiver, tid);
353  acknowledgment->baType = m_mac->GetBaTypeAsOriginator(receiver, tid);
354  acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::BLOCK_ACK);
355  return acknowledgment;
356  }
357 
358  NS_LOG_DEBUG(
359  "A-MPDU using Implicit Block Ack Request policy or BlockAckReq, request Block Ack");
360  auto acknowledgment = std::make_unique<WifiBlockAck>();
361  acknowledgment->blockAckTxVector =
362  GetWifiRemoteStationManager()->GetBlockAckTxVector(receiver, txParams.m_txVector);
363  acknowledgment->baType = m_mac->GetBaTypeAsOriginator(receiver, tid);
364  acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::NORMAL_ACK);
365  return acknowledgment;
366 }
367 
368 std::unique_ptr<WifiAcknowledgment>
370 {
371  NS_LOG_FUNCTION(this << *msdu << &txParams);
372 
373  // Aggregating an MSDU does not change the acknowledgment method
374  return nullptr;
375 }
376 
377 std::unique_ptr<WifiAcknowledgment>
379  const WifiTxParameters& txParams)
380 {
381  NS_LOG_FUNCTION(this << *mpdu << &txParams);
382  NS_ASSERT(txParams.m_txVector.IsDlMu());
384 
385  const WifiMacHeader& hdr = mpdu->GetHeader();
386  Mac48Address receiver = hdr.GetAddr1();
387 
388  const WifiTxParameters::PsduInfo* psduInfo = txParams.GetPsduInfo(receiver);
389 
390  NS_ABORT_MSG_IF(!hdr.IsQosData(),
391  "QoS data frames only can be aggregated when transmitting a "
392  "DL MU PPDU acknowledged via a sequence of BAR and BA frames");
393  uint8_t tid = hdr.GetQosTid();
395 
396  NS_ASSERT(!txParams.m_acknowledgment ||
398 
399  WifiDlMuBarBaSequence* acknowledgment = nullptr;
400  if (txParams.m_acknowledgment)
401  {
402  acknowledgment = static_cast<WifiDlMuBarBaSequence*>(txParams.m_acknowledgment.get());
403  }
404 
405  if (psduInfo)
406  {
407  // an MPDU addressed to the same receiver has been already added
408  NS_ASSERT(acknowledgment);
409 
410  if ((acknowledgment->stationsSendBlockAckReqTo.find(receiver) !=
411  acknowledgment->stationsSendBlockAckReqTo.end()) ||
412  (acknowledgment->stationsReplyingWithBlockAck.find(receiver) !=
413  acknowledgment->stationsReplyingWithBlockAck.end()))
414  {
415  // the receiver either is already listed among the stations that will
416  // receive a BlockAckReq frame or is the station that will immediately
417  // respond with a BlockAck frame, hence no change is needed
418  return nullptr;
419  }
420 
421  // the receiver was scheduled for responding immediately with a Normal Ack.
422  // Given that we are adding an MPDU, the receiver must be scheduled for
423  // responding immediately with a Block Ack
424  NS_ASSERT(acknowledgment->stationsReplyingWithNormalAck.size() == 1 &&
425  acknowledgment->stationsReplyingWithNormalAck.begin()->first == receiver);
426 
427  // acknowledgment points to the m_acknowledgment member of txParams, which is
428  // passed as const reference because it must not be modified. Therefore, we
429  // make a copy of the object pointed to by acknowledgment and make changes to
430  // the copy
431  acknowledgment = new WifiDlMuBarBaSequence(*acknowledgment);
432  acknowledgment->stationsReplyingWithNormalAck.clear();
433 
434  acknowledgment->stationsReplyingWithBlockAck.emplace(
435  receiver,
437  GetWifiRemoteStationManager()->GetBlockAckTxVector(receiver, txParams.m_txVector),
438  m_mac->GetBaTypeAsOriginator(receiver, tid)});
439  return std::unique_ptr<WifiDlMuBarBaSequence>(acknowledgment);
440  }
441 
442  // we get here if this is the first MPDU for this receiver
443  auto htFem = DynamicCast<HtFrameExchangeManager>(m_mac->GetFrameExchangeManager(m_linkId));
444  NS_ASSERT(htFem);
445  if (auto bar = htFem->GetBar(QosUtilsMapTidToAc(tid), tid, receiver);
446  bar || (acknowledgment && (!acknowledgment->stationsReplyingWithNormalAck.empty() ||
447  !acknowledgment->stationsReplyingWithBlockAck.empty())))
448  {
449  // there is a pending BlockAckReq for this receiver or another receiver
450  // was selected for immediate response.
451  // Add this receiver to the list of stations receiving a BlockAckReq.
452  if (acknowledgment)
453  {
454  // txParams.m_acknowledgment points to an existing WifiDlMuBarBaSequence object.
455  // We have to return a copy of this object including the needed changes
456  acknowledgment = new WifiDlMuBarBaSequence(*acknowledgment);
457  }
458  else
459  {
460  // we have to create a new WifiDlMuBarBaSequence object
461  acknowledgment = new WifiDlMuBarBaSequence;
462  }
463 
464  NS_LOG_DEBUG("Adding STA " << receiver
465  << " to the list of stations receiving a BlockAckReq");
466  acknowledgment->stationsSendBlockAckReqTo.emplace(
467  receiver,
469  GetWifiRemoteStationManager()->GetBlockAckTxVector(receiver, txParams.m_txVector),
470  m_mac->GetBarTypeAsOriginator(receiver, tid),
471  GetWifiRemoteStationManager()->GetBlockAckTxVector(receiver, txParams.m_txVector),
472  m_mac->GetBaTypeAsOriginator(receiver, tid)});
473 
474  acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::BLOCK_ACK);
475  return std::unique_ptr<WifiDlMuBarBaSequence>(acknowledgment);
476  }
477 
478  // Add the receiver as the station that will immediately reply with a Normal Ack
479  if (acknowledgment)
480  {
481  // txParams.m_acknowledgment points to an existing WifiDlMuBarBaSequence object.
482  // We have to return a copy of this object including the needed changes
483  acknowledgment = new WifiDlMuBarBaSequence(*acknowledgment);
484  }
485  else
486  {
487  // we have to create a new WifiDlMuBarBaSequence object
488  acknowledgment = new WifiDlMuBarBaSequence;
489  }
490 
491  NS_LOG_DEBUG("Adding STA " << receiver
492  << " as the station that will immediately reply with a Normal Ack");
493  acknowledgment->stationsReplyingWithNormalAck.emplace(
494  receiver,
496  GetWifiRemoteStationManager()->GetAckTxVector(receiver, txParams.m_txVector)});
497 
498  acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::NORMAL_ACK);
499  return std::unique_ptr<WifiDlMuBarBaSequence>(acknowledgment);
500 }
501 
502 std::unique_ptr<WifiAcknowledgment>
504  const WifiTxParameters& txParams)
505 {
506  NS_LOG_FUNCTION(this << *mpdu << &txParams);
507  NS_ASSERT(txParams.m_txVector.IsDlMu());
509 
510  const WifiMacHeader& hdr = mpdu->GetHeader();
511  Mac48Address receiver = hdr.GetAddr1();
512 
513  const WifiTxParameters::PsduInfo* psduInfo = txParams.GetPsduInfo(receiver);
514 
515  NS_ASSERT(!txParams.m_acknowledgment ||
517 
518  WifiDlMuTfMuBar* acknowledgment = nullptr;
519  if (txParams.m_acknowledgment)
520  {
521  acknowledgment = static_cast<WifiDlMuTfMuBar*>(txParams.m_acknowledgment.get());
522  }
523 
524  if (!psduInfo)
525  {
526  // we get here if this is the first MPDU for this receiver.
527  Ptr<ApWifiMac> apMac = DynamicCast<ApWifiMac>(m_mac);
528  NS_ABORT_MSG_IF(!apMac, "HE APs only can send DL MU PPDUs");
529  uint16_t staId = apMac->GetAssociationId(receiver, m_linkId);
530 
531  NS_ABORT_MSG_IF(!hdr.IsQosData(),
532  "QoS data frames only can be aggregated when transmitting a "
533  "DL MU PPDU acknowledged via a MU-BAR sent as SU frame");
534  uint8_t tid = hdr.GetQosTid();
535 
536  // Add the receiver to the list of stations that will reply with a Block Ack
537  if (acknowledgment)
538  {
539  // txParams.m_acknowledgment points to an existing WifiDlMuTfMuBar object.
540  // We have to return a copy of this object including the needed changes
541  acknowledgment = new WifiDlMuTfMuBar(*acknowledgment);
542  }
543  else
544  {
545  // we have to create a new WifiDlMuTfMuBar object
546  acknowledgment = new WifiDlMuTfMuBar;
547  }
548 
549  // determine the TX vector used to send the BlockAck frame
550  WifiTxVector blockAckTxVector;
551  auto preamble = IsEht(txParams.m_txVector.GetPreambleType()) ? WIFI_PREAMBLE_EHT_TB
553  blockAckTxVector.SetPreambleType(preamble);
554  blockAckTxVector.SetChannelWidth(txParams.m_txVector.GetChannelWidth());
555  // 800ns GI is not allowed for HE TB
556  blockAckTxVector.SetGuardInterval(
557  std::max<uint16_t>(txParams.m_txVector.GetGuardInterval(), 1600));
558  const auto& userInfo = txParams.m_txVector.GetHeMuUserInfo(staId);
559  blockAckTxVector.SetHeMuUserInfo(
560  staId,
561  {userInfo.ru, std::min(userInfo.mcs, m_maxMcsForBlockAckInTbPpdu), userInfo.nss});
562 
563  NS_LOG_DEBUG("Adding STA "
564  << receiver
565  << " to the list of stations that will be solicited by the MU-BAR");
567  acknowledgment->stationsReplyingWithBlockAck.emplace(
568  receiver,
569  WifiDlMuTfMuBar::BlockAckInfo{edca->GetBaManager()->GetBlockAckReqHeader(
570  mpdu->GetOriginal()->GetHeader().GetAddr1(),
571  tid),
572  blockAckTxVector,
573  m_mac->GetBaTypeAsOriginator(receiver, tid)});
574 
575  acknowledgment->barTypes.push_back(m_mac->GetBarTypeAsOriginator(receiver, tid));
576  acknowledgment->muBarTxVector =
577  GetWifiRemoteStationManager()->GetRtsTxVector(receiver,
578  txParams.m_txVector.GetChannelWidth());
579  acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::BLOCK_ACK);
580  return std::unique_ptr<WifiDlMuTfMuBar>(acknowledgment);
581  }
582 
583  // an MPDU addressed to the same receiver has been already added
584  NS_ASSERT(acknowledgment);
585  NS_ABORT_MSG_IF(!hdr.IsQosData(),
586  "QoS data frames only can be aggregated when transmitting a DL MU PPDU");
587 
588  // no change is needed
589  return nullptr;
590 }
591 
592 std::unique_ptr<WifiAcknowledgment>
594  const WifiTxParameters& txParams)
595 {
596  NS_LOG_FUNCTION(this << *mpdu << &txParams);
597  NS_ASSERT(txParams.m_txVector.IsDlMu());
599 
600  const WifiMacHeader& hdr = mpdu->GetHeader();
601  Mac48Address receiver = hdr.GetAddr1();
602 
603  const WifiTxParameters::PsduInfo* psduInfo = txParams.GetPsduInfo(receiver);
604 
605  NS_ASSERT(!txParams.m_acknowledgment ||
607 
608  WifiDlMuAggregateTf* acknowledgment = nullptr;
609  if (txParams.m_acknowledgment)
610  {
611  acknowledgment = static_cast<WifiDlMuAggregateTf*>(txParams.m_acknowledgment.get());
612  }
613 
614  if (!psduInfo)
615  {
616  // we get here if this is the first MPDU for this receiver.
617  Ptr<ApWifiMac> apMac = DynamicCast<ApWifiMac>(m_mac);
618  NS_ABORT_MSG_IF(!apMac, "HE APs only can send DL MU PPDUs");
619  uint16_t staId = apMac->GetAssociationId(receiver, m_linkId);
620 
621  NS_ABORT_MSG_IF(!hdr.IsQosData(),
622  "QoS data frames only can be aggregated when transmitting a "
623  "DL MU PPDU acknowledged via a sequence of BAR and BA frames");
624  uint8_t tid = hdr.GetQosTid();
625 
626  // Add the receiver to the list of stations that will reply with a Block Ack
627  if (acknowledgment)
628  {
629  // txParams.m_acknowledgment points to an existing WifiDlMuAggregateTf object.
630  // We have to return a copy of this object including the needed changes
631  acknowledgment = new WifiDlMuAggregateTf(*acknowledgment);
632  }
633  else
634  {
635  // we have to create a new WifiDlMuAggregateTf object
636  acknowledgment = new WifiDlMuAggregateTf;
637  }
638 
639  // determine the TX vector used to send the BlockAck frame
640  WifiTxVector blockAckTxVector;
641  auto preamble = IsEht(txParams.m_txVector.GetPreambleType()) ? WIFI_PREAMBLE_EHT_TB
643  blockAckTxVector.SetPreambleType(preamble);
644  blockAckTxVector.SetChannelWidth(txParams.m_txVector.GetChannelWidth());
645  // 800ns GI is not allowed for HE TB
646  blockAckTxVector.SetGuardInterval(
647  std::max<uint16_t>(txParams.m_txVector.GetGuardInterval(), 1600));
648  const auto& userInfo = txParams.m_txVector.GetHeMuUserInfo(staId);
649  blockAckTxVector.SetHeMuUserInfo(
650  staId,
651  {userInfo.ru, std::min(userInfo.mcs, m_maxMcsForBlockAckInTbPpdu), userInfo.nss});
652 
653  NS_LOG_DEBUG("Adding STA " << receiver
654  << " to the list of stations that will reply with a Block Ack");
656  acknowledgment->stationsReplyingWithBlockAck.emplace(
657  receiver,
659  GetMuBarSize({m_mac->GetBarTypeAsOriginator(receiver, tid)}),
660  edca->GetBaManager()->GetBlockAckReqHeader(
661  mpdu->GetOriginal()->GetHeader().GetAddr1(),
662  tid),
663  blockAckTxVector,
664  m_mac->GetBaTypeAsOriginator(receiver, tid)});
665 
666  acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::NO_EXPLICIT_ACK);
667  return std::unique_ptr<WifiDlMuAggregateTf>(acknowledgment);
668  }
669 
670  // an MPDU addressed to the same receiver has been already added
671  NS_ASSERT(acknowledgment);
673  !hdr.IsQosData(),
674  "QoS data and MU-BAR Trigger frames only can be aggregated when transmitting a DL MU PPDU");
675 
676  // no change is needed
677  return nullptr;
678 }
679 
680 std::unique_ptr<WifiAcknowledgment>
682  const WifiTxParameters& txParams)
683 {
684  NS_LOG_FUNCTION(this << *mpdu << &txParams);
685  NS_ASSERT(mpdu->GetHeader().IsTrigger());
686 
687  Ptr<ApWifiMac> apMac = DynamicCast<ApWifiMac>(m_mac);
688  NS_ABORT_MSG_IF(!apMac, "HE APs only can send Trigger Frames");
689 
690  auto heFem = DynamicCast<HeFrameExchangeManager>(m_mac->GetFrameExchangeManager(m_linkId));
691  NS_ABORT_MSG_IF(!heFem, "HE APs only can send Trigger Frames");
692 
693  CtrlTriggerHeader trigger;
694  mpdu->GetPacket()->PeekHeader(trigger);
695 
696  if (trigger.IsBasic())
697  {
698  // the only supported ack method for now is through a multi-STA BlockAck frame
699  auto acknowledgment = std::make_unique<WifiUlMuMultiStaBa>();
700 
701  for (const auto& userInfo : trigger)
702  {
703  uint16_t aid12 = userInfo.GetAid12();
704 
705  if (aid12 == NO_USER_STA_ID)
706  {
707  NS_LOG_INFO("Unallocated RU");
708  continue;
709  }
710  NS_ABORT_MSG_IF(aid12 == 0 || aid12 > 2007, "Allocation of RA-RUs is not supported");
711 
712  NS_ASSERT(apMac->GetStaList(m_linkId).find(aid12) != apMac->GetStaList(m_linkId).end());
713  Mac48Address staAddress = apMac->GetStaList(m_linkId).find(aid12)->second;
714 
715  // find a TID for which a BA agreement exists with the given originator
716  uint8_t tid = 0;
717  while (tid < 8 && !m_mac->GetBaAgreementEstablishedAsRecipient(staAddress, tid))
718  {
719  tid++;
720  }
721  NS_ASSERT_MSG(tid < 8,
722  "No Block Ack agreement established with originator " << staAddress);
723 
724  std::size_t index = acknowledgment->baType.m_bitmapLen.size();
725  acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(staAddress, tid),
726  index);
727 
728  // we assume the Block Acknowledgment context is used for the multi-STA BlockAck frame
729  // (since it requires the longest TX time due to the presence of a bitmap)
730  acknowledgment->baType.m_bitmapLen.push_back(
731  m_mac->GetBaTypeAsRecipient(staAddress, tid).m_bitmapLen.at(0));
732  }
733 
734  uint16_t staId = trigger.begin()->GetAid12();
735  acknowledgment->tbPpduTxVector = trigger.GetHeTbTxVector(staId);
736  acknowledgment->multiStaBaTxVector = GetWifiRemoteStationManager()->GetBlockAckTxVector(
737  apMac->GetStaList(m_linkId).find(staId)->second,
738  acknowledgment->tbPpduTxVector);
739  return acknowledgment;
740  }
741  else if (trigger.IsBsrp())
742  {
743  return std::make_unique<WifiNoAck>();
744  }
745 
746  return nullptr;
747 }
748 
749 } // namespace ns3
#define min(a, b)
Definition: 80211b.c:41
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.
Headers for Trigger frames.
Definition: ctrl-headers.h:942
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:62
an EUI-48 address
Definition: mac48-address.h:46
bool IsGroup() const
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
Ptr< BlockAckManager > GetBaManager()
Get the Block Ack Manager associated with this QosTxop.
Definition: qos-txop.cc:286
uint16_t GetBaBufferSize(Mac48Address address, uint8_t tid) const
Definition: qos-txop.cc:292
virtual Time GetRemainingTxop(uint8_t linkId) const
Return the remaining duration in the current TXOP on the given link.
Definition: qos-txop.cc:636
uint16_t GetBaStartingSequence(Mac48Address address, uint8_t tid) const
Definition: qos-txop.cc:298
bool IsStrictlyPositive() const
Exactly equivalent to t > 0.
Definition: nstime.h:351
Time GetTxopLimit() const
Return the TXOP limit.
Definition: txop.cc:490
Ptr< WifiMacQueue > GetWifiMacQueue() const
Return the packet queue associated with this Txop.
Definition: txop.cc:231
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:931
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:864
BlockAckType GetBaTypeAsRecipient(Mac48Address originator, uint8_t tid) const
Definition: wifi-mac.cc:1719
BlockAckType GetBaTypeAsOriginator(const Mac48Address &recipient, uint8_t tid) const
Definition: wifi-mac.cc:1701
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:545
BlockAckReqType GetBarTypeAsOriginator(const Mac48Address &recipient, uint8_t tid) const
Definition: wifi-mac.cc:1710
OriginatorAgreementOptConstRef GetBaAgreementEstablishedAsOriginator(Mac48Address recipient, uint8_t tid) const
Definition: wifi-mac.cc:1679
Ptr< QosTxop > GetQosTxop(AcIndex ac) const
Accessor for a specified EDCA object.
Definition: wifi-mac.cc:499
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
#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:182
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:191
@ WIFI_PREAMBLE_EHT_TB
@ WIFI_PREAMBLE_HE_TB
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition: boolean.cc:124
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
bool IsEht(WifiPreamble preamble)
Return true if a preamble corresponds to an EHT transmission.
Ptr< const AttributeChecker > MakeEnumChecker(T v, std::string n, Ts... args)
Make an EnumChecker pre-configured with a set of allowed values by name.
Definition: enum.h:194
static constexpr uint16_t NO_USER_STA_ID
STA_ID for a RU that is intended for no user (Section 26.11.1 802.11ax-2021)
uint32_t GetMuBarSize(std::list< BlockAckReqType > types)
Return the total MU-BAR size (including FCS trailer).
Definition: wifi-utils.cc:86
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Definition: boolean.h:86
Ptr< const AttributeAccessor > MakeDoubleAccessor(T1 a1)
Definition: double.h:43
static constexpr uint16_t SEQNO_SPACE_SIZE
Size of the space of sequence numbers.
Definition: wifi-utils.h:185
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Definition: uinteger.h:46
std::vector< uint8_t > m_bitmapLen
Length (bytes) of included bitmaps.
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...
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.
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