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
34namespace ns3 {
35
36NS_LOG_COMPONENT_DEFINE ("WifiDefaultAckManager");
37
38NS_OBJECT_ENSURE_REGISTERED (WifiDefaultAckManager);
39
40TypeId
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
90uint16_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
134bool
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
166std::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
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
331std::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
341std::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
470std::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
554std::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
637std::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
658 for (const auto& userInfo : trigger)
659 {
660 uint16_t aid12 = userInfo.GetAid12 ();
661
662 if (aid12 == 2046)
663 {
664 NS_LOG_INFO ("Unallocated RU");
665 continue;
666 }
667 NS_ABORT_MSG_IF (aid12 == 0 || aid12 > 2007, "Allocation of RA-RUs is not supported");
668
669 NS_ASSERT (apMac->GetStaList ().find (aid12) != apMac->GetStaList ().end ());
670 Mac48Address staAddress = apMac->GetStaList ().find (aid12)->second;
671
672 // find a TID for which a BA agreement exists with the given originator
673 uint8_t tid = 0;
674 while (tid < 8 && !heFem->GetBaAgreementEstablished (staAddress, tid))
675 {
676 tid++;
677 }
678 NS_ASSERT_MSG (tid < 8, "No Block Ack agreement established with originator " << staAddress);
679
680 std::size_t index = acknowledgment->baType.m_bitmapLen.size ();
681 acknowledgment->stationsReceivingMultiStaBa.emplace (std::make_pair (staAddress, tid), index);
682
683 // we assume the Block Acknowledgment context is used for the multi-STA BlockAck frame
684 // (since it requires the longest TX time due to the presence of a bitmap)
685 acknowledgment->baType.m_bitmapLen.push_back (heFem->GetBlockAckType (staAddress, tid).m_bitmapLen.at (0));
686 }
687
688 uint16_t staId = trigger.begin ()->GetAid12 ();
689 acknowledgment->tbPpduTxVector = trigger.GetHeTbTxVector (staId);
690 acknowledgment->multiStaBaTxVector = m_mac->GetWifiRemoteStationManager ()->GetBlockAckTxVector (apMac->GetStaList ().find (staId)->second,
691 acknowledgment->tbPpduTxVector);
692 return std::unique_ptr<WifiUlMuMultiStaBa> (acknowledgment);
693 }
694 else if (trigger.IsBsrp ())
695 {
696 return std::unique_ptr<WifiAcknowledgment> (new WifiNoAck);
697 }
698
699 return nullptr;
700}
701
702} //namespace ns3
#define min(a, b)
Definition: 80211b.c:42
AttributeValue implementation for Boolean.
Definition: boolean.h:37
Headers for Trigger frames.
Definition: ctrl-headers.h:886
bool IsBsrp(void) const
Check if this is a Buffer Status Report Poll Trigger frame.
bool IsBasic(void) const
Check if this is a Basic Trigger frame.
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Definition: double.h:41
Hold variables of type enum.
Definition: enum.h:55
static WifiMode GetHeMcs(uint8_t index)
Return the HE MCS corresponding to the provided index.
Definition: he-phy.cc:1015
an EUI-48 address
Definition: mac48-address.h:44
bool IsGroup(void) const
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:74
uint16_t GetBaBufferSize(Mac48Address address, uint8_t tid) const
Definition: qos-txop.cc:255
virtual Time GetRemainingTxop(void) const
Return the remaining duration in the current TXOP.
Definition: qos-txop.cc:565
bool GetBaAgreementEstablished(Mac48Address address, uint8_t tid) const
Definition: qos-txop.cc:249
BlockAckType GetBlockAckType(Mac48Address recipient, uint8_t tid) const
Definition: qos-txop.cc:527
Ptr< BlockAckManager > GetBaManager(void)
Get the Block Ack Manager associated with this QosTxop.
Definition: qos-txop.cc:243
BlockAckReqType GetBlockAckReqType(Mac48Address recipient, uint8_t tid) const
Definition: qos-txop.cc:521
uint16_t GetBaStartingSequence(Mac48Address address, uint8_t tid) const
Definition: qos-txop.cc:261
bool IsStrictlyPositive(void) const
Exactly equivalent to t > 0.
Definition: nstime.h:332
Ptr< WifiMacQueue > GetWifiMacQueue() const
Return the packet queue associated with this Txop.
Definition: txop.cc:154
Time GetTxopLimit(void) const
Return the TXOP limit.
Definition: txop.cc:280
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:922
Hold an unsigned integer type.
Definition: uinteger.h:44
WifiAckManager is an abstract base class.
Ptr< WifiMac > m_mac
MAC which is using this Acknowledgment Manager.
WifiDefaultAckManager is the default ack manager.
static TypeId GetTypeId(void)
Get the type ID.
bool m_useExplicitBar
true for sending BARs, false for using Implicit BAR policy
uint8_t m_maxMcsForBlockAckInTbPpdu
Max MCS used to send a BlockAck in a TB PPDU.
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...
double m_baThreshold
Threshold to determine when a BlockAck must be requested.
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...
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.
WifiAcknowledgment::Method m_dlMuAckType
Type of the ack sequence for DL MU PPDUs.
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.
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.
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...
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...
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...
Implements the IEEE 802.11 MAC header.
uint8_t GetQosTid(void) const
Return the Traffic ID of a QoS header.
bool IsTrigger(void) const
Return true if the header is a Trigger header.
bool HasData(void) const
Return true if the header type is DATA and is not DATA_NULL.
bool IsQosData(void) const
Return true if the Type is DATA and Subtype is one of the possible values for QoS Data.
uint16_t GetSequenceNumber(void) const
Return the sequence number of the header.
bool IsBlockAckReq(void) const
Return true if the header is a BlockAckRequest header.
Mac48Address GetAddr1(void) const
Return the address in the Address 1 field.
This class stores the TX parameters (TX vector, protection mechanism, acknowledgment mechanism,...
std::unique_ptr< WifiProtection > m_protection
protection method
uint32_t GetSize(Mac48Address receiver) const
Get the size in bytes of the (A-)MPDU addressed to the given receiver.
std::unique_ptr< WifiAcknowledgment > m_acknowledgment
acknowledgment method
const PsduInfo * GetPsduInfo(Mac48Address receiver) const
Get a pointer to the information about the PSDU addressed to the given receiver, if present,...
WifiTxVector m_txVector
TXVECTOR of the frame being prepared.
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
bool IsDlMu(void) const
Return true if this TX vector is used for a downlink multi-user transmission.
void SetChannelWidth(uint16_t channelWidth)
Sets the selected channelWidth (in MHz)
void SetGuardInterval(uint16_t guardInterval)
Sets the guard interval duration (in nanoseconds)
void SetHeMuUserInfo(uint16_t staId, HeMuUserInfo userInfo)
Set the HE MU user-specific transmission information for the given STA-ID.
HeMuUserInfo GetHeMuUserInfo(uint16_t staId) const
Get the HE MU user-specific transmission information for the given STA-ID.
uint16_t GetChannelWidth(void) const
uint16_t GetGuardInterval(void) const
bool IsUlMu(void) const
Return true if this TX vector is used for an uplink multi-user transmission.
void SetPreambleType(WifiPreamble preamble)
Sets the preamble type.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:67
#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 AttributeChecker > MakeBooleanChecker(void)
Definition: boolean.cc:121
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Definition: boolean.h:85
Ptr< const AttributeAccessor > MakeDoubleAccessor(T1 a1)
Definition: double.h:42
Ptr< const AttributeAccessor > MakeEnumAccessor(T1 a1)
Definition: enum.h:205
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Definition: uinteger.h:45
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition: abort.h:50
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:273
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:281
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:45
AcIndex QosUtilsMapTidToAc(uint8_t tid)
Maps TID (Traffic ID) to Access classes.
Definition: qos-utils.cc:126
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
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
@ WIFI_PREAMBLE_HE_TB
Every class exported by the ns3 library is enclosed in the ns3 namespace.
uint32_t GetMuBarSize(std::list< BlockAckReqType > types)
Return the total MU-BAR size (including FCS trailer).
Definition: wifi-utils.cc:83
const uint16_t SEQNO_SPACE_SIZE
Size of the space of sequence numbers.
Definition: wifi-utils.h:131
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:134
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:162
std::vector< uint8_t > m_bitmapLen
Length (bytes) of included bitmaps.
WifiAckAfterTbPpdu is used when a station prepares a TB PPDU to send in response to a Basic Trigger F...
void SetQosAckPolicy(Mac48Address receiver, uint8_t tid, WifiMacHeader::QosAckPolicy ackPolicy)
Set the QoS Ack policy to use for the MPDUs addressed to the given receiver and belonging to the give...
WifiBarBlockAck specifies that a BlockAckReq is sent to solicit a Block Ack response.
BlockAckType baType
BlockAck type.
WifiTxVector blockAckTxVector
BlockAck TXVECTOR.
WifiTxVector blockAckReqTxVector
BlockAckReq TXVECTOR.
BlockAckReqType barType
BlockAckReq type.
WifiBlockAck specifies that acknowledgment via Block Ack is required.
WifiTxVector blockAckTxVector
BlockAck TXVECTOR.
BlockAckType baType
BlockAck type.
information related to a BlockAck frame sent by a station
WifiDlMuAggregateTf specifies that a DL MU PPDU made of PSDUs including each a MU-BAR Trigger Frame i...
std::map< Mac48Address, BlockAckInfo > stationsReplyingWithBlockAck
Set of stations replying with a BlockAck frame.
information related to an Ack frame sent by a station
information related to a BlockAck frame sent by a station
information related to a BlockAckReq frame sent to a station
WifiDlMuBarBaSequence specifies that a DL MU PPDU is acknowledged through a sequence of BlockAckReq a...
std::map< Mac48Address, BlockAckReqInfo > stationsSendBlockAckReqTo
Set of stations receiving a BlockAckReq frame and replying with a BlockAck frame.
std::map< Mac48Address, BlockAckInfo > stationsReplyingWithBlockAck
Set of stations replying with a BlockAck frame (no more than one)
std::map< Mac48Address, AckInfo > stationsReplyingWithNormalAck
Set of stations replying with an Ack frame (no more than one)
information related to a BlockAck frame sent by a station
WifiDlMuTfMuBar specifies that a DL MU PPDU is followed after a SIFS duration by a MU-BAR Trigger Fra...
std::list< BlockAckReqType > barTypes
BAR types.
std::map< Mac48Address, BlockAckInfo > stationsReplyingWithBlockAck
Set of stations replying with a BlockAck frame.
WifiTxVector muBarTxVector
TXVECTOR used to transmit the MU-BAR Trigger Frame.
WifiNoAck specifies that no acknowledgment is required.
WifiNormalAck specifies that acknowledgment via Normal Ack is required.
WifiTxVector ackTxVector
Ack TXVECTOR.
information about the frame being prepared for a specific receiver
std::map< uint8_t, std::set< uint16_t > > seqNumbers
set of the sequence numbers of the MPDUs added for each TID
WifiUlMuMultiStaBa specifies that a Basic Trigger Frame is being sent to solicit TB PPDUs that will b...
BlockAckType baType
BlockAck type.
WifiTxVector tbPpduTxVector
TXVECTOR for a TB PPDU.
WifiTxVector multiStaBaTxVector
TXVECTOR for the Multi-STA BlockAck.
std::map< std::pair< Mac48Address, uint8_t >, std::size_t > stationsReceivingMultiStaBa
Map (originator, tid) pairs to the their index in baType.