A Discrete-Event Network Simulator
API
wifi-default-ack-manager.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2020 Universita' degli Studi di Napoli Federico II
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Author: Stefano Avallone <stavallo@unina.it>
19  */
20 
21 #include "ns3/log.h"
23 #include "wifi-tx-parameters.h"
24 #include "wifi-mac-queue-item.h"
25 #include "qos-utils.h"
26 #include "wifi-mac-queue.h"
27 #include "wifi-protection.h"
28 #include "ap-wifi-mac.h"
29 #include "ctrl-headers.h"
30 #include "ns3/he-phy.h"
31 #include "ns3/he-frame-exchange-manager.h"
32 
33 
34 namespace ns3 {
35 
36 NS_LOG_COMPONENT_DEFINE ("WifiDefaultAckManager");
37 
38 NS_OBJECT_ENSURE_REGISTERED (WifiDefaultAckManager);
39 
40 TypeId
42 {
43  static TypeId tid = TypeId ("ns3::WifiDefaultAckManager")
45  .SetGroupName ("Wifi")
46  .AddConstructor<WifiDefaultAckManager> ()
47  .AddAttribute ("UseExplicitBar",
48  "Specify whether to send Block Ack Requests (if true) or use"
49  " Implicit Block Ack Request ack policy (if false).",
50  BooleanValue (false),
53  .AddAttribute ("BaThreshold",
54  "Immediate acknowledgment is requested upon transmission of a frame "
55  "whose sequence number is distant at least BaThreshold multiplied "
56  "by the transmit window size from the starting sequence number of "
57  "the transmit window. Set to zero to request a response for every "
58  "transmitted frame.",
59  DoubleValue (0.0),
61  MakeDoubleChecker<double> (0.0, 1.0))
62  .AddAttribute ("DlMuAckSequenceType",
63  "Type of the acknowledgment sequence for DL MU PPDUs.",
67  WifiAcknowledgment::DL_MU_TF_MU_BAR, "DL_MU_TF_MU_BAR",
68  WifiAcknowledgment::DL_MU_AGGREGATE_TF, "DL_MU_AGGREGATE_TF"))
69  .AddAttribute ("MaxBlockAckMcs",
70  "The MCS used to send a BlockAck in a TB PPDU is the minimum between "
71  "the MCS used for the PSDU sent in the preceding DL MU PPDU and the "
72  "value of this attribute.",
73  UintegerValue (5),
75  MakeUintegerChecker<uint8_t> (0, 11))
76  ;
77  return tid;
78 }
79 
81 {
82  NS_LOG_FUNCTION (this);
83 }
84 
86 {
88 }
89 
90 uint16_t
92  const WifiTxParameters& txParams) const
93 {
94  NS_LOG_FUNCTION (this << *mpdu << &txParams);
95 
96  const WifiMacHeader& hdr = mpdu->GetHeader ();
97  Mac48Address receiver = hdr.GetAddr1 ();
98 
99  uint8_t tid = hdr.GetQosTid ();
100  Ptr<QosTxop> edca = m_mac->GetQosTxop (tid);
101  NS_ABORT_MSG_IF (!edca->GetBaAgreementEstablished (receiver, tid),
102  "An established Block Ack agreement is required");
103 
104  uint16_t startingSeq = edca->GetBaStartingSequence (receiver, tid);
105  uint16_t maxDistFromStartingSeq = (mpdu->GetHeader ().GetSequenceNumber () - startingSeq + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE;
106  NS_ABORT_MSG_IF (maxDistFromStartingSeq >= SEQNO_SPACE_HALF_SIZE,
107  "The given QoS data frame is too old");
108 
109  const WifiTxParameters::PsduInfo* psduInfo = txParams.GetPsduInfo (receiver);
110 
111  if (psduInfo == nullptr || psduInfo->seqNumbers.find (tid) == psduInfo->seqNumbers.end ())
112  {
113  // there are no aggregated MPDUs (so far)
114  return maxDistFromStartingSeq;
115  }
116 
117  for (const auto& seqNumber : psduInfo->seqNumbers.at (tid))
118  {
119  if (!QosUtilsIsOldPacket (startingSeq, seqNumber))
120  {
121  uint16_t currDistToStartingSeq = (seqNumber - startingSeq + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE;
122 
123  if (currDistToStartingSeq > maxDistFromStartingSeq)
124  {
125  maxDistFromStartingSeq = currDistToStartingSeq;
126  }
127  }
128  }
129 
130  NS_LOG_DEBUG ("Returning " << maxDistFromStartingSeq);
131  return maxDistFromStartingSeq;
132 }
133 
134 bool
136  const WifiTxParameters& txParams) const
137 {
138  NS_LOG_FUNCTION (this << *mpdu << &txParams);
139 
140  uint8_t tid = mpdu->GetHeader ().GetQosTid ();
141  Mac48Address receiver = mpdu->GetHeader ().GetAddr1 ();
142  Ptr<QosTxop> edca = m_mac->GetQosTxop (tid);
143 
144  // An immediate response (Ack or Block Ack) is needed if any of the following holds:
145  // * the maximum distance between the sequence number of an MPDU to transmit
146  // and the starting sequence number of the transmit window is greater than
147  // or equal to the window size multiplied by the BaThreshold
148  // * no other frame belonging to this BA agreement is queued (because, in such
149  // a case, a Block Ack is not going to be requested anytime soon)
150  // * this is the initial frame of a transmission opportunity and it is not
151  // protected by RTS/CTS (see Annex G.3 of IEEE 802.11-2016)
152  if (m_baThreshold > 0
153  && GetMaxDistFromStartingSeq (mpdu, txParams) < m_baThreshold * edca->GetBaBufferSize (receiver, tid)
154  && (edca->GetWifiMacQueue ()->GetNPackets (tid, receiver)
155  + edca->GetBaManager ()->GetRetransmitQueue ()->GetNPackets (tid, receiver) > 1)
156  && !(edca->GetTxopLimit ().IsStrictlyPositive ()
157  && edca->GetRemainingTxop () == edca->GetTxopLimit ()
158  && !(txParams.m_protection && txParams.m_protection->method == WifiProtection::RTS_CTS)))
159  {
160  return false;
161  }
162 
163  return true;
164 }
165 
166 std::unique_ptr<WifiAcknowledgment>
168  const WifiTxParameters& txParams)
169 {
170  NS_LOG_FUNCTION (this << *mpdu << &txParams);
171 
172  // If the TXVECTOR indicates a DL MU PPDU, call a separate method
173  if (txParams.m_txVector.IsDlMu ())
174  {
175  switch (m_dlMuAckType)
176  {
178  return GetAckInfoIfBarBaSequence (mpdu, txParams);
180  return GetAckInfoIfTfMuBar (mpdu, txParams);
182  return GetAckInfoIfAggregatedMuBar (mpdu, txParams);
183  default:
184  NS_ABORT_MSG ("Unknown DL acknowledgment method");
185  return nullptr;
186  }
187  }
188 
189  const WifiMacHeader& hdr = mpdu->GetHeader ();
190  Mac48Address receiver = hdr.GetAddr1 ();
191 
192  // Acknowledgment for TB PPDUs
193  if (txParams.m_txVector.IsUlMu ())
194  {
195  if (hdr.IsQosData () && !hdr.HasData ())
196  {
197  // QoS Null frame
198  WifiNoAck* acknowledgment = nullptr;
199 
200  if (txParams.m_acknowledgment)
201  {
203  acknowledgment = static_cast<WifiNoAck*> (txParams.m_acknowledgment.get ());
204  acknowledgment = new WifiNoAck (*acknowledgment);
205  }
206  else
207  {
208  acknowledgment = new WifiNoAck;
209  }
210  acknowledgment->SetQosAckPolicy (receiver, hdr.GetQosTid (), WifiMacHeader::NO_ACK);
211  return std::unique_ptr<WifiAcknowledgment> (acknowledgment);
212  }
213 
214  if (txParams.m_acknowledgment)
215  {
217  return nullptr;
218  }
219 
220  WifiAckAfterTbPpdu* acknowledgment = new WifiAckAfterTbPpdu;
221  if (hdr.IsQosData ())
222  {
223  acknowledgment->SetQosAckPolicy (receiver, hdr.GetQosTid (), WifiMacHeader::NORMAL_ACK);
224  }
225  return std::unique_ptr<WifiAcknowledgment> (acknowledgment);
226  }
227 
228  // if this is a Trigger Frame, call a separate method
229  if (hdr.IsTrigger ())
230  {
231  return TryUlMuTransmission (mpdu, txParams);
232  }
233 
234  // if the current protection method (if any) is already BLOCK_ACK or BAR_BLOCK_ACK,
235  // it will not change by adding an MPDU
236  if (txParams.m_acknowledgment
237  && (txParams.m_acknowledgment->method == WifiAcknowledgment::BLOCK_ACK
238  || txParams.m_acknowledgment->method == WifiAcknowledgment::BAR_BLOCK_ACK))
239  {
240  return nullptr;
241  }
242 
243  if (receiver.IsGroup ())
244  {
245  NS_ABORT_MSG_IF (txParams.GetSize (receiver) > 0,
246  "Unicast frames only can be aggregated");
247  WifiNoAck* acknowledgment = new WifiNoAck;
248  if (hdr.IsQosData ())
249  {
250  acknowledgment->SetQosAckPolicy (receiver, hdr.GetQosTid (),
252  }
253  return std::unique_ptr<WifiAcknowledgment> (acknowledgment);
254  }
255 
256  if ((!hdr.IsQosData ()
257  || !m_mac->GetQosTxop (hdr.GetQosTid ())->GetBaAgreementEstablished (receiver, hdr.GetQosTid ()))
258  && !hdr.IsBlockAckReq ())
259  {
260  NS_LOG_DEBUG ("Non-QoS data frame or Block Ack agreement not established, request Normal Ack");
261  WifiNormalAck* acknowledgment = new WifiNormalAck;
262  acknowledgment->ackTxVector = m_mac->GetWifiRemoteStationManager ()->GetAckTxVector (receiver, txParams.m_txVector);
263  if (hdr.IsQosData ())
264  {
265  acknowledgment->SetQosAckPolicy (receiver, hdr.GetQosTid (), WifiMacHeader::NORMAL_ACK);
266  }
267  return std::unique_ptr<WifiAcknowledgment> (acknowledgment);
268  }
269 
270  // we get here if mpdu is a QoS data frame related to an established Block Ack agreement
271  // or mpdu is a BlockAckReq frame
272  if (!hdr.IsBlockAckReq () && !IsResponseNeeded (mpdu, txParams))
273  {
274  NS_LOG_DEBUG ("A response is not needed: no ack for now, use Block Ack policy");
275  if (txParams.m_acknowledgment
276  && txParams.m_acknowledgment->method == WifiAcknowledgment::NONE)
277  {
278  // no change if the ack method is already NONE
279  return nullptr;
280  }
281 
282  WifiNoAck* acknowledgment = new WifiNoAck;
283  if (hdr.IsQosData ())
284  {
285  acknowledgment->SetQosAckPolicy (receiver, hdr.GetQosTid (),
287  }
288  return std::unique_ptr<WifiAcknowledgment> (acknowledgment);
289  }
290 
291  // we get here if a response is needed
292  uint8_t tid = GetTid (mpdu->GetPacket (), hdr);
293  if (!hdr.IsBlockAckReq ()
294  && txParams.GetSize (receiver) == 0
295  && hdr.GetSequenceNumber ()
296  == m_mac->GetQosTxop (tid)->GetBaStartingSequence (receiver, tid))
297  {
298  NS_LOG_DEBUG ("Sending a single MPDU, no previous frame to ack: request Normal Ack");
299  WifiNormalAck* acknowledgment = new WifiNormalAck;
300  acknowledgment->ackTxVector = m_mac->GetWifiRemoteStationManager ()->GetAckTxVector (receiver, txParams.m_txVector);
301  acknowledgment->SetQosAckPolicy (receiver, tid, WifiMacHeader::NORMAL_ACK);
302  return std::unique_ptr<WifiAcknowledgment> (acknowledgment);
303  }
304 
305  // we get here if multiple MPDUs are being/have been sent
306  if (!hdr.IsBlockAckReq ()
307  && (txParams.GetSize (receiver) == 0 || m_useExplicitBar))
308  {
309  // in case of single MPDU, there are previous unacknowledged frames, thus
310  // we cannot use Implicit Block Ack Request policy, otherwise we get a
311  // normal ack as response
312  NS_LOG_DEBUG ("Request to schedule a Block Ack Request");
313 
314  WifiBarBlockAck* acknowledgment = new WifiBarBlockAck;
315  acknowledgment->blockAckReqTxVector = m_mac->GetWifiRemoteStationManager ()->GetBlockAckTxVector (receiver, txParams.m_txVector);
316  acknowledgment->blockAckTxVector = acknowledgment->blockAckReqTxVector;
317  acknowledgment->barType = m_mac->GetQosTxop (tid)->GetBlockAckReqType (receiver, tid);
318  acknowledgment->baType = m_mac->GetQosTxop (tid)->GetBlockAckType (receiver, tid);
319  acknowledgment->SetQosAckPolicy (receiver, tid, WifiMacHeader::BLOCK_ACK);
320  return std::unique_ptr<WifiAcknowledgment> (acknowledgment);
321  }
322 
323  NS_LOG_DEBUG ("A-MPDU using Implicit Block Ack Request policy or BlockAckReq, request Block Ack");
324  WifiBlockAck* acknowledgment = new WifiBlockAck;
325  acknowledgment->blockAckTxVector = m_mac->GetWifiRemoteStationManager ()->GetBlockAckTxVector (receiver, txParams.m_txVector);
326  acknowledgment->baType = m_mac->GetQosTxop (tid)->GetBlockAckType (receiver, tid);
327  acknowledgment->SetQosAckPolicy (receiver, tid, WifiMacHeader::NORMAL_ACK);
328  return std::unique_ptr<WifiAcknowledgment> (acknowledgment);
329 }
330 
331 std::unique_ptr<WifiAcknowledgment>
333  const WifiTxParameters& txParams)
334 {
335  NS_LOG_FUNCTION (this << *msdu << &txParams);
336 
337  // Aggregating an MSDU does not change the acknowledgment method
338  return nullptr;
339 }
340 
341 std::unique_ptr<WifiAcknowledgment>
343  const WifiTxParameters& txParams)
344 {
345  NS_LOG_FUNCTION (this << *mpdu << &txParams);
346  NS_ASSERT (txParams.m_txVector.IsDlMu ());
348 
349  const WifiMacHeader& hdr = mpdu->GetHeader ();
350  Mac48Address receiver = hdr.GetAddr1 ();
351 
352  const WifiTxParameters::PsduInfo* psduInfo = txParams.GetPsduInfo (receiver);
353 
354  NS_ABORT_MSG_IF (!hdr.IsQosData (),
355  "QoS data frames only can be aggregated when transmitting a "
356  "DL MU PPDU acknowledged via a sequence of BAR and BA frames");
357  uint8_t tid = hdr.GetQosTid ();
358  Ptr<QosTxop> edca = m_mac->GetQosTxop (QosUtilsMapTidToAc (tid));
359 
360  NS_ASSERT (!txParams.m_acknowledgment
362 
363  WifiDlMuBarBaSequence* acknowledgment = nullptr;
364  if (txParams.m_acknowledgment)
365  {
366  acknowledgment = static_cast<WifiDlMuBarBaSequence*> (txParams.m_acknowledgment.get ());
367  }
368 
369  if (psduInfo != nullptr)
370  {
371  // an MPDU addressed to the same receiver has been already added
372  NS_ASSERT (acknowledgment != nullptr);
373 
374  if ((acknowledgment->stationsSendBlockAckReqTo.find (receiver)
375  != acknowledgment->stationsSendBlockAckReqTo.end ())
376  || (acknowledgment->stationsReplyingWithBlockAck.find (receiver)
377  != acknowledgment->stationsReplyingWithBlockAck.end ()))
378  {
379  // the receiver either is already listed among the stations that will
380  // receive a BlockAckReq frame or is the station that will immediately
381  // respond with a BlockAck frame, hence no change is needed
382  return nullptr;
383  }
384 
385  // the receiver was scheduled for responding immediately with a Normal Ack.
386  // Given that we are adding an MPDU, the receiver must be scheduled for
387  // responding immediately with a Block Ack
388  NS_ASSERT (acknowledgment->stationsReplyingWithNormalAck.size () == 1
389  && acknowledgment->stationsReplyingWithNormalAck.begin ()->first == receiver);
390 
391 
392  // acknowledgment points to the m_acknowledgment member of txParams, which is
393  // passed as const reference because it must not be modified. Therefore, we
394  // make a copy of the object pointed to by acknowledgment and make changes to
395  // the copy
396  acknowledgment = new WifiDlMuBarBaSequence (*acknowledgment);
397  acknowledgment->stationsReplyingWithNormalAck.clear ();
398 
399  acknowledgment->stationsReplyingWithBlockAck.emplace
400  (receiver,
402  {
403  m_mac->GetWifiRemoteStationManager ()->GetBlockAckTxVector (receiver, txParams.m_txVector),
404  edca->GetBlockAckType (receiver, tid)
405  });
406  return std::unique_ptr<WifiDlMuBarBaSequence> (acknowledgment);
407  }
408 
409  // we get here if this is the first MPDU for this receiver
410  if (edca->GetBaManager ()->GetBar (true, tid, receiver) != 0
411  || (acknowledgment != nullptr
412  && (!acknowledgment->stationsReplyingWithNormalAck.empty ()
413  || !acknowledgment->stationsReplyingWithBlockAck.empty ())))
414  {
415  // there is a pending BlockAckReq for this receiver or another receiver
416  // was selected for immediate response.
417  // Add this receiver to the list of stations receiving a BlockAckReq.
418  if (acknowledgment != nullptr)
419  {
420  // txParams.m_acknowledgment points to an existing WifiDlMuBarBaSequence object.
421  // We have to return a copy of this object including the needed changes
422  acknowledgment = new WifiDlMuBarBaSequence (*acknowledgment);
423  }
424  else
425  {
426  // we have to create a new WifiDlMuBarBaSequence object
427  acknowledgment = new WifiDlMuBarBaSequence;
428  }
429 
430  NS_LOG_DEBUG ("Adding STA " << receiver << " to the list of stations receiving a BlockAckReq");
431  acknowledgment->stationsSendBlockAckReqTo.emplace
432  (receiver,
434  {
435  m_mac->GetWifiRemoteStationManager ()->GetBlockAckTxVector (receiver, txParams.m_txVector),
436  edca->GetBlockAckReqType (receiver, tid),
437  m_mac->GetWifiRemoteStationManager ()->GetBlockAckTxVector (receiver, txParams.m_txVector),
438  edca->GetBlockAckType (receiver, tid)
439  });
440 
441  acknowledgment->SetQosAckPolicy (receiver, tid, WifiMacHeader::BLOCK_ACK);
442  return std::unique_ptr<WifiDlMuBarBaSequence> (acknowledgment);
443  }
444 
445  // Add the receiver as the station that will immediately reply with a Normal Ack
446  if (acknowledgment != nullptr)
447  {
448  // txParams.m_acknowledgment points to an existing WifiDlMuBarBaSequence object.
449  // We have to return a copy of this object including the needed changes
450  acknowledgment = new WifiDlMuBarBaSequence (*acknowledgment);
451  }
452  else
453  {
454  // we have to create a new WifiDlMuBarBaSequence object
455  acknowledgment = new WifiDlMuBarBaSequence;
456  }
457 
458  NS_LOG_DEBUG ("Adding STA " << receiver << " as the station that will immediately reply with a Normal Ack");
459  acknowledgment->stationsReplyingWithNormalAck.emplace
460  (receiver,
462  {
463  m_mac->GetWifiRemoteStationManager ()->GetAckTxVector (receiver, txParams.m_txVector)
464  });
465 
466  acknowledgment->SetQosAckPolicy (receiver, tid, WifiMacHeader::NORMAL_ACK);
467  return std::unique_ptr<WifiDlMuBarBaSequence> (acknowledgment);
468 }
469 
470 std::unique_ptr<WifiAcknowledgment>
472  const WifiTxParameters& txParams)
473 {
474  NS_LOG_FUNCTION (this << *mpdu << &txParams);
475  NS_ASSERT (txParams.m_txVector.IsDlMu ());
477 
478  const WifiMacHeader& hdr = mpdu->GetHeader ();
479  Mac48Address receiver = hdr.GetAddr1 ();
480 
481  const WifiTxParameters::PsduInfo* psduInfo = txParams.GetPsduInfo (receiver);
482 
483  NS_ASSERT (!txParams.m_acknowledgment
485 
486  WifiDlMuTfMuBar* acknowledgment = nullptr;
487  if (txParams.m_acknowledgment)
488  {
489  acknowledgment = static_cast<WifiDlMuTfMuBar*> (txParams.m_acknowledgment.get ());
490  }
491 
492  if (psduInfo == nullptr)
493  {
494  // we get here if this is the first MPDU for this receiver.
495  Ptr<ApWifiMac> apMac = DynamicCast<ApWifiMac> (m_mac);
496  NS_ABORT_MSG_IF (apMac == 0, "HE APs only can send DL MU PPDUs");
497  uint16_t staId = apMac->GetAssociationId (receiver);
498 
499  NS_ABORT_MSG_IF (!hdr.IsQosData (),
500  "QoS data frames only can be aggregated when transmitting a "
501  "DL MU PPDU acknowledged via a MU-BAR sent as SU frame");
502  uint8_t tid = hdr.GetQosTid ();
503 
504  // Add the receiver to the list of stations that will reply with a Block Ack
505  if (acknowledgment != nullptr)
506  {
507  // txParams.m_acknowledgment points to an existing WifiDlMuTfMuBar object.
508  // We have to return a copy of this object including the needed changes
509  acknowledgment = new WifiDlMuTfMuBar (*acknowledgment);
510  }
511  else
512  {
513  // we have to create a new WifiDlMuTfMuBar object
514  acknowledgment = new WifiDlMuTfMuBar;
515  }
516 
517  // determine the TX vector used to send the BlockAck frame
518  WifiTxVector blockAckTxVector;
520  blockAckTxVector.SetChannelWidth (txParams.m_txVector.GetChannelWidth ());
521  blockAckTxVector.SetGuardInterval (txParams.m_txVector.GetGuardInterval ());
522  const auto& userInfo = txParams.m_txVector.GetHeMuUserInfo (staId);
523  blockAckTxVector.SetHeMuUserInfo (staId, {userInfo.ru,
524  HePhy::GetHeMcs (std::min (userInfo.mcs.GetMcsValue (),
526  userInfo.nss});
527 
528  NS_LOG_DEBUG ("Adding STA " << receiver << " to the list of stations that will be solicited by the MU-BAR");
529  Ptr<QosTxop> edca = m_mac->GetQosTxop (QosUtilsMapTidToAc (tid));
530  acknowledgment->stationsReplyingWithBlockAck.emplace
531  (receiver,
533  {
534  edca->GetBaManager ()->GetBlockAckReqHeader (receiver, tid),
535  blockAckTxVector,
536  edca->GetBlockAckType (receiver, tid)
537  });
538 
539  acknowledgment->barTypes.push_back (edca->GetBlockAckReqType (receiver, tid));
540  acknowledgment->muBarTxVector = m_mac->GetWifiRemoteStationManager ()->GetRtsTxVector (receiver);
541  acknowledgment->SetQosAckPolicy (receiver, tid, WifiMacHeader::BLOCK_ACK);
542  return std::unique_ptr<WifiDlMuTfMuBar> (acknowledgment);
543  }
544 
545  // an MPDU addressed to the same receiver has been already added
546  NS_ASSERT (acknowledgment != nullptr);
547  NS_ABORT_MSG_IF (!hdr.IsQosData (),
548  "QoS data frames only can be aggregated when transmitting a DL MU PPDU");
549 
550  // no change is needed
551  return nullptr;
552 }
553 
554 std::unique_ptr<WifiAcknowledgment>
556  const WifiTxParameters& txParams)
557 {
558  NS_LOG_FUNCTION (this << *mpdu << &txParams);
559  NS_ASSERT (txParams.m_txVector.IsDlMu ());
561 
562  const WifiMacHeader& hdr = mpdu->GetHeader ();
563  Mac48Address receiver = hdr.GetAddr1 ();
564 
565  const WifiTxParameters::PsduInfo* psduInfo = txParams.GetPsduInfo (receiver);
566 
567  NS_ASSERT (!txParams.m_acknowledgment
569 
570  WifiDlMuAggregateTf* acknowledgment = nullptr;
571  if (txParams.m_acknowledgment)
572  {
573  acknowledgment = static_cast<WifiDlMuAggregateTf*> (txParams.m_acknowledgment.get ());
574  }
575 
576  if (psduInfo == nullptr)
577  {
578  // we get here if this is the first MPDU for this receiver.
579  Ptr<ApWifiMac> apMac = DynamicCast<ApWifiMac> (m_mac);
580  NS_ABORT_MSG_IF (apMac == 0, "HE APs only can send DL MU PPDUs");
581  uint16_t staId = apMac->GetAssociationId (receiver);
582 
583  NS_ABORT_MSG_IF (!hdr.IsQosData (),
584  "QoS data frames only can be aggregated when transmitting a "
585  "DL MU PPDU acknowledged via a sequence of BAR and BA frames");
586  uint8_t tid = hdr.GetQosTid ();
587 
588  // Add the receiver to the list of stations that will reply with a Block Ack
589  if (acknowledgment != nullptr)
590  {
591  // txParams.m_acknowledgment points to an existing WifiDlMuAggregateTf object.
592  // We have to return a copy of this object including the needed changes
593  acknowledgment = new WifiDlMuAggregateTf (*acknowledgment);
594  }
595  else
596  {
597  // we have to create a new WifiDlMuAggregateTf object
598  acknowledgment = new WifiDlMuAggregateTf;
599  }
600 
601  // determine the TX vector used to send the BlockAck frame
602  WifiTxVector blockAckTxVector;
604  blockAckTxVector.SetChannelWidth (txParams.m_txVector.GetChannelWidth ());
605  blockAckTxVector.SetGuardInterval (txParams.m_txVector.GetGuardInterval ());
606  const auto& userInfo = txParams.m_txVector.GetHeMuUserInfo (staId);
607  blockAckTxVector.SetHeMuUserInfo (staId, {userInfo.ru,
608  HePhy::GetHeMcs (std::min (userInfo.mcs.GetMcsValue (),
610  userInfo.nss});
611 
612  NS_LOG_DEBUG ("Adding STA " << receiver << " to the list of stations that will reply with a Block Ack");
613  Ptr<QosTxop> edca = m_mac->GetQosTxop (QosUtilsMapTidToAc (tid));
614  acknowledgment->stationsReplyingWithBlockAck.emplace
615  (receiver,
617  {
618  GetMuBarSize ({edca->GetBlockAckReqType (receiver, tid)}),
619  edca->GetBaManager ()->GetBlockAckReqHeader (receiver, tid),
620  blockAckTxVector,
621  edca->GetBlockAckType (receiver, tid)
622  });
623 
624  acknowledgment->SetQosAckPolicy (receiver, tid, WifiMacHeader::NO_EXPLICIT_ACK);
625  return std::unique_ptr<WifiDlMuAggregateTf> (acknowledgment);
626  }
627 
628  // an MPDU addressed to the same receiver has been already added
629  NS_ASSERT (acknowledgment != nullptr);
630  NS_ABORT_MSG_IF (!hdr.IsQosData (),
631  "QoS data and MU-BAR Trigger frames only can be aggregated when transmitting a DL MU PPDU");
632 
633  // no change is needed
634  return nullptr;
635 }
636 
637 std::unique_ptr<WifiAcknowledgment>
639  const WifiTxParameters& txParams)
640 {
641  NS_LOG_FUNCTION (this << *mpdu << &txParams);
642  NS_ASSERT (mpdu->GetHeader ().IsTrigger ());
643 
644  Ptr<ApWifiMac> apMac = DynamicCast<ApWifiMac> (m_mac);
645  NS_ABORT_MSG_IF (apMac == nullptr, "HE APs only can send Trigger Frames");
646 
647  Ptr<HeFrameExchangeManager> heFem = DynamicCast<HeFrameExchangeManager> (m_mac->GetFrameExchangeManager ());
648  NS_ABORT_MSG_IF (heFem == nullptr, "HE APs only can send Trigger Frames");
649 
650  CtrlTriggerHeader trigger;
651  mpdu->GetPacket ()->PeekHeader (trigger);
652 
653  if (trigger.IsBasic ())
654  {
655  // the only supported ack method for now is through a multi-STA BlockAck frame
656  WifiUlMuMultiStaBa* acknowledgment = new WifiUlMuMultiStaBa;
657  acknowledgment->baType.m_variant = BlockAckType::MULTI_STA;
658 
659  for (const auto& userInfo : trigger)
660  {
661  uint16_t aid12 = userInfo.GetAid12 ();
662 
663  if (aid12 == 2046)
664  {
665  NS_LOG_INFO ("Unallocated RU");
666  continue;
667  }
668  NS_ABORT_MSG_IF (aid12 == 0 || aid12 > 2007, "Allocation of RA-RUs is not supported");
669 
670  NS_ASSERT (apMac->GetStaList ().find (aid12) != apMac->GetStaList ().end ());
671  Mac48Address staAddress = apMac->GetStaList ().find (aid12)->second;
672 
673  // find a TID for which a BA agreement exists with the given originator
674  uint8_t tid = 0;
675  while (tid < 8 && !heFem->GetBaAgreementEstablished (staAddress, tid))
676  {
677  tid++;
678  }
679  NS_ASSERT_MSG (tid < 8, "No Block Ack agreement established with originator " << staAddress);
680 
681  std::size_t index = acknowledgment->baType.m_bitmapLen.size ();
682  acknowledgment->stationsReceivingMultiStaBa.emplace (std::make_pair (staAddress, tid), index);
683 
684  // we assume the Block Acknowledgment context is used for the multi-STA BlockAck frame
685  // (since it requires the longest TX time due to the presence of a bitmap)
686  acknowledgment->baType.m_bitmapLen.push_back (heFem->GetBlockAckType (staAddress, tid).m_bitmapLen.at (0));
687  }
688 
689  uint16_t staId = trigger.begin ()->GetAid12 ();
690  acknowledgment->tbPpduTxVector = trigger.GetHeTbTxVector (staId);
691  acknowledgment->multiStaBaTxVector = m_mac->GetWifiRemoteStationManager ()->GetBlockAckTxVector (apMac->GetStaList ().find (staId)->second,
692  acknowledgment->tbPpduTxVector);
693  return std::unique_ptr<WifiUlMuMultiStaBa> (acknowledgment);
694  }
695  else if (trigger.IsBsrp ())
696  {
697  return std::unique_ptr<WifiAcknowledgment> (new WifiNoAck);
698  }
699 
700  return nullptr;
701 }
702 
703 } //namespace ns3
std::map< Mac48Address, BlockAckInfo > stationsReplyingWithBlockAck
Set of stations replying with a BlockAck frame.
virtual std::unique_ptr< WifiAcknowledgment > GetAckInfoIfBarBaSequence(Ptr< const WifiMacQueueItem > 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
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:73
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by "...
AttributeValue implementation for Boolean.
Definition: boolean.h:36
Headers for Trigger frames.
Definition: ctrl-headers.h:885
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition: abort.h:50
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
WifiAcknowledgment::Method m_dlMuAckType
Type of the ack sequence for DL MU PPDUs.
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:45
void SetChannelWidth(uint16_t channelWidth)
Sets the selected channelWidth (in MHz)
#define min(a, b)
Definition: 80211b.c:42
information related to a BlockAckReq frame sent to a station
virtual std::unique_ptr< WifiAcknowledgment > TryAddMpdu(Ptr< const WifiMacQueueItem > 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 > GetAckInfoIfTfMuBar(Ptr< const WifiMacQueueItem > mpdu, const WifiTxParameters &txParams)
Compute the information about the acknowledgment of the current multi-user frame (as described by the...
std::unique_ptr< WifiProtection > m_protection
protection method
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:85
WifiDlMuBarBaSequence specifies that a DL MU PPDU is acknowledged through a sequence of BlockAckReq a...
Mac48Address GetAddr1(void) const
Return the address in the Address 1 field.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file...
Definition: assert.h:67
const uint16_t SEQNO_SPACE_HALF_SIZE
Size of the half the space of sequence numbers (used to determine old packets)
Definition: wifi-utils.h:225
WifiTxVector tbPpduTxVector
TXVECTOR for a TB PPDU.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
WifiTxVector ackTxVector
Ack TXVECTOR.
Ptr< BlockAckManager > GetBaManager(void)
Get the Block Ack Manager associated with this QosTxop.
Definition: qos-txop.cc:155
std::map< Mac48Address, BlockAckInfo > stationsReplyingWithBlockAck
Set of stations replying with a BlockAck frame.
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:281
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:178
bool IsStrictlyPositive(void) const
Exactly equivalent to t > 0.
Definition: nstime.h:333
uint16_t GetBaStartingSequence(Mac48Address address, uint8_t tid) const
Definition: qos-txop.cc:173
uint16_t GetGuardInterval(void) const
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
virtual Time GetRemainingTxop(void) const
Return the remaining duration in the current TXOP.
Definition: qos-txop.cc:598
HeMuUserInfo GetHeMuUserInfo(uint16_t staId) const
Get the HE MU user-specific transmission information for the given STA-ID.
WifiTxVector blockAckReqTxVector
BlockAckReq TXVECTOR.
BlockAckType baType
BlockAck type.
std::map< std::pair< Mac48Address, uint8_t >, std::size_t > stationsReceivingMultiStaBa
Map (originator, tid) pairs to the their index in baType.
static WifiMode GetHeMcs(uint8_t index)
Return the HE MCS corresponding to the provided index.
Definition: he-phy.cc:951
bool IsTrigger(void) const
Return true if the header is a Trigger header.
enum Variant m_variant
Block Ack variant.
WifiTxVector muBarTxVector
TXVECTOR used to transmit the MU-BAR Trigger Frame.
BlockAckType baType
BlockAck type.
WifiTxVector multiStaBaTxVector
TXVECTOR for the Multi-STA BlockAck.
information related to a BlockAck frame sent by a station
virtual std::unique_ptr< WifiAcknowledgment > GetAckInfoIfAggregatedMuBar(Ptr< const WifiMacQueueItem > mpdu, const WifiTxParameters &txParams)
Compute the information about the acknowledgment of the current multi-user frame (as described by the...
bool IsBlockAckReq(void) const
Return true if the header is a BlockAckRequest header.
information related to a BlockAck frame sent by a station
Hold variables of type enum.
Definition: enum.h:54
void SetGuardInterval(uint16_t guardInterval)
Sets the guard interval duration (in nanoseconds)
Hold an unsigned integer type.
Definition: uinteger.h:44
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:203
std::map< Mac48Address, BlockAckInfo > stationsReplyingWithBlockAck
Set of stations replying with a BlockAck frame (no more than one)
const PsduInfo * GetPsduInfo(Mac48Address receiver) const
Get a pointer to the information about the PSDU addressed to the given receiver, if present...
AcIndex QosUtilsMapTidToAc(uint8_t tid)
Maps TID (Traffic ID) to Access classes.
Definition: qos-utils.cc:126
uint8_t GetQosTid(void) const
Return the Traffic ID of a QoS header.
static TypeId GetTypeId(void)
Get the type ID.
std::list< BlockAckReqType > barTypes
BAR types.
WifiTxVector blockAckTxVector
BlockAck TXVECTOR.
WifiNoAck specifies that no acknowledgment is required.
WifiUlMuMultiStaBa specifies that a Basic Trigger Frame is being sent to solicit TB PPDUs that will b...
WifiAckManager is an abstract base class.
uint32_t GetMuBarSize(std::list< BlockAckReqType > types)
Return the total MU-BAR size (including FCS trailer).
Definition: wifi-utils.cc:192
void SetHeMuUserInfo(uint16_t staId, HeMuUserInfo userInfo)
Set the HE MU user-specific transmission information for the given STA-ID.
WifiTxVector m_txVector
TXVECTOR of the frame being prepared.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
uint16_t GetSequenceNumber(void) const
Return the sequence number of the header.
BlockAckType GetBlockAckType(Mac48Address recipient, uint8_t tid) const
Definition: qos-txop.cc:478
void SetPreambleType(WifiPreamble preamble)
Sets the preamble type.
WifiTxVector blockAckTxVector
BlockAck TXVECTOR.
double m_baThreshold
Threshold to determine when a BlockAck must be requested.
WifiDefaultAckManager is the default ack manager.
WifiBarBlockAck specifies that a BlockAckReq is sent to solicit a Block Ack response.
std::map< uint8_t, std::set< uint16_t > > seqNumbers
set of the sequence numbers of the MPDUs added for each TID
an EUI-48 address
Definition: mac48-address.h:43
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:187
virtual std::unique_ptr< WifiAcknowledgment > TryAggregateMsdu(Ptr< const WifiMacQueueItem > msdu, const WifiTxParameters &txParams) override
Determine the acknowledgment method to use if the given MSDU is aggregated to the current frame...
WifiBlockAck specifies that acknowledgment via Block Ack is required.
information about the frame being prepared for a specific receiver
bool IsGroup(void) const
uint32_t GetSize(Mac48Address receiver) const
Get the size in bytes of the (A-)MPDU addressed to the given receiver.
bool IsDlMu(void) const
Return true if this TX vector is used for a downlink multi-user transmission.
#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:88
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:42
virtual std::unique_ptr< WifiAcknowledgment > TryUlMuTransmission(Ptr< const WifiMacQueueItem > mpdu, const WifiTxParameters &txParams)
Calculate the acknowledgment method for the TB PPDUs solicited by the given Trigger Frame...
uint16_t GetMaxDistFromStartingSeq(Ptr< const WifiMacQueueItem > mpdu, const WifiTxParameters &txParams) const
Get the maximum distance between the starting sequence number of the Block Ack agreement which the gi...
bool IsBsrp(void) const
Check if this is a Buffer Status Report Poll Trigger frame.
std::vector< uint8_t > m_bitmapLen
Length (bytes) of included bitmaps.
BlockAckReqType GetBlockAckReqType(Mac48Address recipient, uint8_t tid) const
Definition: qos-txop.cc:472
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
Ptr< RegularWifiMac > m_mac
MAC which is using this Acknowledgment Manager.
information related to a BlockAck frame sent by a station
BlockAckType baType
BlockAck type.
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...
bool IsUlMu(void) const
Return true if this TX vector is used for an uplink multi-user transmission.
bool GetBaAgreementEstablished(Mac48Address address, uint8_t tid) const
Definition: qos-txop.cc:161
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:273
Ptr< const AttributeChecker > MakeBooleanChecker(void)
Definition: boolean.cc:121
Ptr< WifiMacQueue > GetWifiMacQueue() const
Return the packet queue associated with this Txop.
Definition: txop.cc:150
This class stores the TX parameters (TX vector, protection mechanism, acknowledgment mechanism...
uint8_t m_maxMcsForBlockAckInTbPpdu
Max MCS used to send a BlockAck in a TB PPDU.
WifiDlMuAggregateTf specifies that a DL MU PPDU made of PSDUs including each a MU-BAR Trigger Frame i...
uint16_t GetBaBufferSize(Mac48Address address, uint8_t tid) const
Definition: qos-txop.cc:167
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:161
const uint16_t SEQNO_SPACE_SIZE
Size of the space of sequence numbers.
Definition: wifi-utils.h:222
WifiAckAfterTbPpdu is used when a station prepares a TB PPDU to send in response to a Basic Trigger F...
bool IsQosData(void) const
Return true if the Type is DATA and Subtype is one of the possible values for QoS Data...
uint16_t GetChannelWidth(void) const
information related to an Ack frame sent by a station
std::unique_ptr< WifiAcknowledgment > m_acknowledgment
acknowledgment method
BlockAckReqType barType
BlockAckReq type.
WifiNormalAck specifies that acknowledgment via Normal Ack is required.
This class can be used to hold variables of floating point type such as &#39;double&#39; or &#39;float&#39;...
Definition: double.h:41
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:45
a unique identifier for an interface.
Definition: type-id.h:58
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:923
bool IsResponseNeeded(Ptr< const WifiMacQueueItem > mpdu, const WifiTxParameters &txParams) const
Determine whether the (A-)MPDU containing the given MPDU and the MPDUs (if any) included in the given...
WifiDlMuTfMuBar specifies that a DL MU PPDU is followed after a SIFS duration by a MU-BAR Trigger Fra...
bool IsBasic(void) const
Check if this is a Basic Trigger frame.
std::map< Mac48Address, BlockAckReqInfo > stationsSendBlockAckReqTo
Set of stations receiving a BlockAckReq frame and replying with a BlockAck frame. ...
Implements the IEEE 802.11 MAC header.
std::map< Mac48Address, AckInfo > stationsReplyingWithNormalAck
Set of stations replying with an Ack frame (no more than one)
bool HasData(void) const
Return true if the header type is DATA and is not DATA_NULL.
Time GetTxopLimit(void) const
Return the TXOP limit.
Definition: txop.cc:274