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"
22 #include "wifi-default-ack-manager.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
GetTypeId(void)41 WifiDefaultAckManager::GetTypeId (void)
42 {
43   static TypeId tid = TypeId ("ns3::WifiDefaultAckManager")
44     .SetParent<WifiAckManager> ()
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),
51                    MakeBooleanAccessor (&WifiDefaultAckManager::m_useExplicitBar),
52                    MakeBooleanChecker ())
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),
60                    MakeDoubleAccessor (&WifiDefaultAckManager::m_baThreshold),
61                    MakeDoubleChecker<double> (0.0, 1.0))
62     .AddAttribute ("DlMuAckSequenceType",
63                    "Type of the acknowledgment sequence for DL MU PPDUs.",
64                    EnumValue (WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE),
65                    MakeEnumAccessor (&WifiDefaultAckManager::m_dlMuAckType),
66                    MakeEnumChecker (WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE, "DL_MU_BAR_BA_SEQUENCE",
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),
74                    MakeUintegerAccessor (&WifiDefaultAckManager::m_maxMcsForBlockAckInTbPpdu),
75                    MakeUintegerChecker<uint8_t> (0, 11))
76   ;
77   return tid;
78 }
79 
WifiDefaultAckManager()80 WifiDefaultAckManager::WifiDefaultAckManager ()
81 {
82   NS_LOG_FUNCTION (this);
83 }
84 
~WifiDefaultAckManager()85 WifiDefaultAckManager::~WifiDefaultAckManager ()
86 {
87   NS_LOG_FUNCTION_NOARGS ();
88 }
89 
90 uint16_t
GetMaxDistFromStartingSeq(Ptr<const WifiMacQueueItem> mpdu,const WifiTxParameters & txParams) const91 WifiDefaultAckManager::GetMaxDistFromStartingSeq (Ptr<const WifiMacQueueItem> mpdu,
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
IsResponseNeeded(Ptr<const WifiMacQueueItem> mpdu,const WifiTxParameters & txParams) const135 WifiDefaultAckManager::IsResponseNeeded (Ptr<const WifiMacQueueItem> mpdu,
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 ()->GetNBufferedPackets (receiver, tid) > 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>
TryAddMpdu(Ptr<const WifiMacQueueItem> mpdu,const WifiTxParameters & txParams)167 WifiDefaultAckManager::TryAddMpdu (Ptr<const WifiMacQueueItem> mpdu,
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         {
177           case WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE:
178             return GetAckInfoIfBarBaSequence (mpdu, txParams);
179           case WifiAcknowledgment::DL_MU_TF_MU_BAR:
180             return GetAckInfoIfTfMuBar (mpdu, txParams);
181           case WifiAcknowledgment::DL_MU_AGGREGATE_TF:
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             {
202               NS_ASSERT (txParams.m_acknowledgment->method == WifiAcknowledgment::NONE);
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         {
216           NS_ASSERT (txParams.m_acknowledgment->method == WifiAcknowledgment::ACK_AFTER_TB_PPDU);
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 (),
251                                            WifiMacHeader::NO_ACK);
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 (),
286                                            WifiMacHeader::BLOCK_ACK);
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>
TryAggregateMsdu(Ptr<const WifiMacQueueItem> msdu,const WifiTxParameters & txParams)332 WifiDefaultAckManager::TryAggregateMsdu (Ptr<const WifiMacQueueItem> msdu,
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>
GetAckInfoIfBarBaSequence(Ptr<const WifiMacQueueItem> mpdu,const WifiTxParameters & txParams)342 WifiDefaultAckManager::GetAckInfoIfBarBaSequence (Ptr<const WifiMacQueueItem> mpdu,
343                                                   const WifiTxParameters& txParams)
344 {
345   NS_LOG_FUNCTION (this << *mpdu << &txParams);
346   NS_ASSERT (txParams.m_txVector.IsDlMu ());
347   NS_ASSERT (m_dlMuAckType == WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE);
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
361              || txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE);
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,
401           WifiDlMuBarBaSequence::BlockAckInfo
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,
433           WifiDlMuBarBaSequence::BlockAckReqInfo
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,
461       WifiDlMuBarBaSequence::AckInfo
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>
GetAckInfoIfTfMuBar(Ptr<const WifiMacQueueItem> mpdu,const WifiTxParameters & txParams)471 WifiDefaultAckManager::GetAckInfoIfTfMuBar (Ptr<const WifiMacQueueItem> mpdu,
472                                             const WifiTxParameters& txParams)
473 {
474   NS_LOG_FUNCTION (this << *mpdu << &txParams);
475   NS_ASSERT (txParams.m_txVector.IsDlMu ());
476   NS_ASSERT (m_dlMuAckType == WifiAcknowledgment::DL_MU_TF_MU_BAR);
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
484              || txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_TF_MU_BAR);
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;
519       blockAckTxVector.SetPreambleType (WifiPreamble::WIFI_PREAMBLE_HE_TB);
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 (),
525                                                                            m_maxMcsForBlockAckInTbPpdu)),
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,
532           WifiDlMuTfMuBar::BlockAckInfo
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>
GetAckInfoIfAggregatedMuBar(Ptr<const WifiMacQueueItem> mpdu,const WifiTxParameters & txParams)555 WifiDefaultAckManager::GetAckInfoIfAggregatedMuBar (Ptr<const WifiMacQueueItem> mpdu,
556                                                     const WifiTxParameters& txParams)
557 {
558   NS_LOG_FUNCTION (this << *mpdu << &txParams);
559   NS_ASSERT (txParams.m_txVector.IsDlMu ());
560   NS_ASSERT (m_dlMuAckType == WifiAcknowledgment::DL_MU_AGGREGATE_TF);
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
568              || txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF);
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;
603       blockAckTxVector.SetPreambleType (WifiPreamble::WIFI_PREAMBLE_HE_TB);
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 (),
609                                                                            m_maxMcsForBlockAckInTbPpdu)),
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,
616           WifiDlMuAggregateTf::BlockAckInfo
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>
TryUlMuTransmission(Ptr<const WifiMacQueueItem> mpdu,const WifiTxParameters & txParams)638 WifiDefaultAckManager::TryUlMuTransmission (Ptr<const WifiMacQueueItem> mpdu,
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
704