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