A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
wifi-default-ack-manager.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2020 Universita' degli Studi di Napoli Federico II
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Stefano Avallone <stavallo@unina.it>
7 */
8
10
11#include "ap-wifi-mac.h"
12#include "ctrl-headers.h"
13#include "gcr-manager.h"
14#include "qos-utils.h"
15#include "wifi-mac-queue.h"
16#include "wifi-mpdu.h"
17#include "wifi-protection.h"
18#include "wifi-tx-parameters.h"
19
20#include "ns3/he-frame-exchange-manager.h"
21#include "ns3/log.h"
22
23namespace ns3
24{
25
26NS_LOG_COMPONENT_DEFINE("WifiDefaultAckManager");
27
28NS_OBJECT_ENSURE_REGISTERED(WifiDefaultAckManager);
29
30TypeId
32{
33 static TypeId tid =
34 TypeId("ns3::WifiDefaultAckManager")
36 .SetGroupName("Wifi")
37 .AddConstructor<WifiDefaultAckManager>()
38 .AddAttribute("UseExplicitBar",
39 "Specify whether to send Block Ack Requests (if true) or use"
40 " Implicit Block Ack Request ack policy (if false).",
41 BooleanValue(false),
44 .AddAttribute("BaThreshold",
45 "Immediate acknowledgment is requested upon transmission of a frame "
46 "whose sequence number is distant at least BaThreshold multiplied "
47 "by the transmit window size from the starting sequence number of "
48 "the transmit window. Set to zero to request a response for every "
49 "transmitted frame.",
50 DoubleValue(0.0),
53 .AddAttribute(
54 "DlMuAckSequenceType",
55 "Type of the acknowledgment sequence for DL MU PPDUs.",
59 "DL_MU_BAR_BA_SEQUENCE",
61 "DL_MU_TF_MU_BAR",
63 "DL_MU_AGGREGATE_TF"))
64 .AddAttribute("MaxBlockAckMcs",
65 "The MCS used to send a BlockAck in a TB PPDU is the minimum between "
66 "the MCS used for the PSDU sent in the preceding DL MU PPDU and the "
67 "value of this attribute.",
71 return tid;
72}
73
78
83
84uint16_t
86 const WifiTxParameters& txParams) const
87{
88 NS_LOG_FUNCTION(this << *mpdu << &txParams);
89
90 auto receiver = mpdu->GetHeader().GetAddr1();
91 auto origReceiver = mpdu->GetOriginal()->GetHeader().GetAddr1();
92
93 uint8_t tid = mpdu->GetHeader().GetQosTid();
94 Ptr<QosTxop> edca = m_mac->GetQosTxop(tid);
95 NS_ABORT_MSG_IF(!m_mac->GetBaAgreementEstablishedAsOriginator(origReceiver, tid),
96 "An established Block Ack agreement is required");
97
98 uint16_t startingSeq = edca->GetBaStartingSequence(origReceiver, tid);
99 uint16_t maxDistFromStartingSeq = 0;
100
101 const auto* psduInfo = txParams.GetPsduInfo(receiver);
102 NS_ASSERT_MSG(psduInfo && psduInfo->seqNumbers.contains(tid),
103 "There must be at least an MPDU with tid " << +tid);
104
105 const auto& seqNumbers = psduInfo->seqNumbers.at(tid);
106 NS_ASSERT_MSG(seqNumbers.contains(mpdu->GetHeader().GetSequenceNumber()),
107 "The sequence number of the given MPDU is not included in the TX parameters");
108
109 for (const auto& seqNumber : seqNumbers)
110 {
111 NS_ASSERT_MSG(!QosUtilsIsOldPacket(startingSeq, seqNumber),
112 "QoS data frame SeqN=" << seqNumber << " is too old");
113
114 uint16_t currDistToStartingSeq =
115 (seqNumber - startingSeq + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE;
116
117 if (currDistToStartingSeq > maxDistFromStartingSeq)
118 {
119 maxDistFromStartingSeq = currDistToStartingSeq;
120 }
121 }
122
123 NS_LOG_DEBUG("Returning " << maxDistFromStartingSeq);
124 return maxDistFromStartingSeq;
125}
126
127bool
129 const WifiTxParameters& txParams) const
130{
131 NS_LOG_FUNCTION(this << *mpdu << &txParams);
132
133 uint8_t tid = mpdu->GetHeader().GetQosTid();
134 auto receiver = mpdu->GetHeader().GetAddr1();
135 auto origReceiver = mpdu->GetOriginal()->GetHeader().GetAddr1();
136 Ptr<QosTxop> edca = m_mac->GetQosTxop(tid);
137 const auto& seqNumbers = txParams.GetPsduInfo(receiver)->seqNumbers.at(tid);
138
139 // An immediate response (Ack or Block Ack) is needed if any of the following holds:
140 // * the BA threshold is set to zero
141 if (m_baThreshold == 0.0)
142 {
143 return true;
144 }
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 if (GetMaxDistFromStartingSeq(mpdu, txParams) >=
149 m_baThreshold * edca->GetBaBufferSize(origReceiver, tid))
150 {
151 return true;
152 }
153 // * no other frame belonging to this BA agreement is queued (because, in such
154 // a case, a Block Ack is not going to be requested anytime soon)
155 if (auto queueId =
157 edca->GetWifiMacQueue()->GetNPackets(queueId) -
158 edca->GetBaManager()->GetNBufferedPackets(origReceiver, tid) - seqNumbers.size() <
159 1)
160 {
161 return true;
162 }
163 // * the block ack TX window cannot advance because all the MPDUs in the TX window other than
164 // those being transmitted have been already acknowledged
165 if (m_mac->GetBaAgreementEstablishedAsOriginator(origReceiver, tid)
166 ->get()
167 .AllAckedMpdusInTxWindow(seqNumbers))
168 {
169 return true;
170 }
171
172 // * this is the initial frame of a transmission opportunity and it is not
173 // protected by RTS/CTS (see Annex G.3 of IEEE 802.11-2016)
174 if (edca->GetTxopLimit(m_linkId).IsStrictlyPositive() &&
175 edca->GetRemainingTxop(m_linkId) == edca->GetTxopLimit(m_linkId) &&
176 !(txParams.m_protection && txParams.m_protection->method == WifiProtection::RTS_CTS))
177 {
178 return true;
179 }
180
181 return false;
182}
183
184bool
186{
187 NS_ASSERT(mpdu->GetHeader().IsQosData());
188 auto tid = mpdu->GetHeader().GetQosTid();
189 NS_ASSERT(mpdu->IsQueued());
190 auto queue = m_mac->GetTxopQueue(mpdu->GetQueueAc());
191 auto origReceiver = mpdu->GetOriginal()->GetHeader().GetAddr1();
192 auto agreement = m_mac->GetBaAgreementEstablishedAsOriginator(origReceiver, tid);
193 NS_ASSERT(agreement);
194 auto mpduDist = agreement->get().GetDistance(mpdu->GetHeader().GetSequenceNumber());
195
196 Ptr<WifiMpdu> item = queue->PeekByTidAndAddress(tid, origReceiver);
197
198 while (item)
199 {
200 auto itemDist = agreement->get().GetDistance(item->GetHeader().GetSequenceNumber());
201 if (itemDist == mpduDist)
202 {
203 NS_LOG_DEBUG("No previous MPDU in-flight on the same link");
204 return false;
205 }
206 NS_ABORT_MSG_IF(itemDist > mpduDist,
207 "While searching for given MPDU ("
208 << *mpdu << "), found first another one (" << *item
209 << ") with higher sequence number");
210 if (auto linkIds = item->GetInFlightLinkIds(); linkIds.contains(m_linkId))
211 {
212 NS_LOG_DEBUG("Found MPDU inflight on the same link");
213 return true;
214 }
215 item = queue->PeekByTidAndAddress(tid, origReceiver, item);
216 }
217 NS_ABORT_MSG("Should not get here");
218 return false;
219}
220
221std::unique_ptr<WifiAcknowledgment>
223{
224 NS_LOG_FUNCTION(this << *mpdu << &txParams);
225
226 // If the TXVECTOR indicates a DL MU PPDU, call a separate method
227 if (txParams.m_txVector.IsDlMu())
228 {
229 switch (m_dlMuAckType)
230 {
232 return GetAckInfoIfBarBaSequence(mpdu, txParams);
234 return GetAckInfoIfTfMuBar(mpdu, txParams);
236 return GetAckInfoIfAggregatedMuBar(mpdu, txParams);
237 default:
238 NS_ABORT_MSG("Unknown DL acknowledgment method");
239 return nullptr;
240 }
241 }
242
243 const WifiMacHeader& hdr = mpdu->GetHeader();
244 Mac48Address receiver = hdr.GetAddr1();
245
246 // Acknowledgment for TB PPDUs
247 if (txParams.m_txVector.IsUlMu())
248 {
249 if (hdr.IsQosData() && !hdr.HasData())
250 {
251 // QoS Null frame
252 std::unique_ptr<WifiAcknowledgment> acknowledgment;
253
254 if (txParams.m_acknowledgment)
255 {
257 acknowledgment = txParams.m_acknowledgment->Copy();
258 }
259 else
260 {
261 acknowledgment = std::make_unique<WifiNoAck>();
262 }
263 acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::NO_ACK);
264 return acknowledgment;
265 }
266
267 if (txParams.m_acknowledgment)
268 {
270 return nullptr;
271 }
272
273 auto acknowledgment = std::make_unique<WifiAckAfterTbPpdu>();
274 if (hdr.IsQosData())
275 {
276 acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::NORMAL_ACK);
277 }
278 return acknowledgment;
279 }
280
281 // if this is a Trigger Frame, call a separate method
282 if (hdr.IsTrigger())
283 {
284 return TryUlMuTransmission(mpdu, txParams);
285 }
286
287 // if the current acknowledgment method (if any) is already BLOCK_ACK, it will not
288 // change by adding an MPDU
289 if (txParams.m_acknowledgment &&
291 {
292 return nullptr;
293 }
294
295 if (receiver.IsGroup())
296 {
297 // if the current acknowledgment method (if any) is already BAR_BLOCK_ACK, it will not
298 // change by adding an MPDU
299 if (txParams.m_acknowledgment &&
301 {
302 return nullptr;
303 }
304 const auto isGcr = IsGcr(m_mac, hdr);
305 NS_ABORT_MSG_IF(!isGcr && !txParams.LastAddedIsFirstMpdu(receiver),
306 "Unicast frames only can be aggregated if GCR is not used");
307 if (auto apMac = DynamicCast<ApWifiMac>(m_mac);
308 isGcr && apMac->GetGcrManager()->GetRetransmissionPolicyFor(hdr) ==
310 {
311 NS_LOG_DEBUG("Request to schedule a GCR Block Ack Request");
312 const auto recipient =
313 apMac->GetGcrManager()->GetIndividuallyAddressedRecipient(receiver);
314 auto acknowledgment = std::make_unique<WifiBarBlockAck>();
315 acknowledgment->blockAckReqTxVector =
316 GetWifiRemoteStationManager()->GetBlockAckTxVector(recipient, txParams.m_txVector);
317 acknowledgment->blockAckTxVector = acknowledgment->blockAckReqTxVector;
318 acknowledgment->barType = BlockAckReqType::GCR;
319 acknowledgment->baType = BlockAckType::GCR;
320 acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::BLOCK_ACK);
321 return acknowledgment;
322 }
323 auto acknowledgment = std::make_unique<WifiNoAck>();
324 if (hdr.IsQosData())
325 {
326 acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::NO_ACK);
327 }
328 return acknowledgment;
329 }
330
331 if ((!hdr.IsQosData() ||
332 !m_mac->GetBaAgreementEstablishedAsOriginator(receiver, hdr.GetQosTid())) &&
333 !hdr.IsBlockAckReq())
334 {
336 "Non-QoS data frame or Block Ack agreement not established, request Normal Ack");
337 auto acknowledgment = std::make_unique<WifiNormalAck>();
338 acknowledgment->ackTxVector =
339 GetWifiRemoteStationManager()->GetAckTxVector(receiver, txParams.m_txVector);
340 if (hdr.IsQosData())
341 {
342 acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::NORMAL_ACK);
343 }
344 return acknowledgment;
345 }
346
347 // we get here if mpdu is a QoS data frame related to an established Block Ack agreement
348 // or mpdu is a BlockAckReq frame
349 if (!hdr.IsBlockAckReq() && !IsResponseNeeded(mpdu, txParams))
350 {
351 NS_LOG_DEBUG("A response is not needed: no ack for now, use Block Ack policy");
352 if (txParams.m_acknowledgment &&
353 txParams.m_acknowledgment->method == WifiAcknowledgment::NONE)
354 {
355 // no change if the ack method is already NONE
356 return nullptr;
357 }
358
359 auto acknowledgment = std::make_unique<WifiNoAck>();
360 if (hdr.IsQosData())
361 {
362 acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::BLOCK_ACK);
363 }
364 return acknowledgment;
365 }
366
367 // we get here if a response is needed
368 uint8_t tid = GetTid(mpdu->GetPacket(), hdr);
369 if (!hdr.IsBlockAckReq() && txParams.LastAddedIsFirstMpdu(receiver) &&
371 {
372 NS_LOG_DEBUG("Sending a single MPDU, no previous frame to ack: request Normal Ack");
373 auto acknowledgment = std::make_unique<WifiNormalAck>();
374 acknowledgment->ackTxVector =
375 GetWifiRemoteStationManager()->GetAckTxVector(receiver, txParams.m_txVector);
376 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::NORMAL_ACK);
377 return acknowledgment;
378 }
379
380 // we get here if multiple MPDUs are being/have been sent
381 if (!hdr.IsBlockAckReq() && (txParams.LastAddedIsFirstMpdu(receiver) || m_useExplicitBar))
382 {
383 // in case of single MPDU, there are previous unacknowledged frames, thus
384 // we cannot use Implicit Block Ack Request policy, otherwise we get a
385 // normal ack as response
386 NS_LOG_DEBUG("Request to schedule a Block Ack Request");
387
388 auto acknowledgment = std::make_unique<WifiBarBlockAck>();
389 acknowledgment->blockAckReqTxVector =
390 GetWifiRemoteStationManager()->GetBlockAckTxVector(receiver, txParams.m_txVector);
391 acknowledgment->blockAckTxVector = acknowledgment->blockAckReqTxVector;
392 acknowledgment->barType = m_mac->GetBarTypeAsOriginator(receiver, tid);
393 acknowledgment->baType = m_mac->GetBaTypeAsOriginator(receiver, tid);
394 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::BLOCK_ACK);
395 return acknowledgment;
396 }
397
398 if (hdr.IsBlockAckReq())
399 {
400 CtrlBAckRequestHeader baReqHdr;
401 mpdu->GetPacket()->PeekHeader(baReqHdr);
402 if (baReqHdr.IsGcr())
403 {
404 NS_LOG_DEBUG("GCR Block Ack Req, request GCR Block Ack");
405 auto acknowledgment = std::make_unique<WifiBlockAck>();
406 acknowledgment->blockAckTxVector =
407 GetWifiRemoteStationManager()->GetBlockAckTxVector(receiver, txParams.m_txVector);
408 acknowledgment->baType = BlockAckType::GCR;
409 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::NORMAL_ACK);
410 return acknowledgment;
411 }
412 }
413
415 "A-MPDU using Implicit Block Ack Request policy or BlockAckReq, request Block Ack");
416 auto acknowledgment = std::make_unique<WifiBlockAck>();
417 acknowledgment->blockAckTxVector =
418 GetWifiRemoteStationManager()->GetBlockAckTxVector(receiver, txParams.m_txVector);
419 acknowledgment->baType = m_mac->GetBaTypeAsOriginator(receiver, tid);
420 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::NORMAL_ACK);
421 return acknowledgment;
422}
423
424std::unique_ptr<WifiAcknowledgment>
426{
427 NS_LOG_FUNCTION(this << *msdu << &txParams);
428
429 // Aggregating an MSDU does not change the acknowledgment method
430 return nullptr;
431}
432
433std::unique_ptr<WifiAcknowledgment>
435 const WifiTxParameters& txParams)
436{
437 NS_LOG_FUNCTION(this << *mpdu << &txParams);
438 NS_ASSERT(txParams.m_txVector.IsDlMu());
440
441 const WifiMacHeader& hdr = mpdu->GetHeader();
442 Mac48Address receiver = hdr.GetAddr1();
443
445 "QoS data frames only can be aggregated when transmitting a "
446 "DL MU PPDU acknowledged via a sequence of BAR and BA frames");
447 uint8_t tid = hdr.GetQosTid();
448 Ptr<QosTxop> edca = m_mac->GetQosTxop(QosUtilsMapTidToAc(tid));
449
450 NS_ASSERT(!txParams.m_acknowledgment ||
452
453 WifiDlMuBarBaSequence* acknowledgment = nullptr;
454 if (txParams.m_acknowledgment)
455 {
456 acknowledgment = static_cast<WifiDlMuBarBaSequence*>(txParams.m_acknowledgment.get());
457 }
458
459 if (!txParams.LastAddedIsFirstMpdu(receiver))
460 {
461 // an MPDU addressed to the same receiver has been already added
462 NS_ASSERT(acknowledgment);
463
464 if (acknowledgment->stationsSendBlockAckReqTo.contains(receiver) ||
465 acknowledgment->stationsReplyingWithBlockAck.contains(receiver))
466 {
467 // the receiver either is already listed among the stations that will
468 // receive a BlockAckReq frame or is the station that will immediately
469 // respond with a BlockAck frame, hence no change is needed
470 return nullptr;
471 }
472
473 // the receiver was scheduled for responding immediately with a Normal Ack.
474 // Given that we are adding an MPDU, the receiver must be scheduled for
475 // responding immediately with a Block Ack
476 NS_ASSERT(acknowledgment->stationsReplyingWithNormalAck.size() == 1 &&
477 acknowledgment->stationsReplyingWithNormalAck.begin()->first == receiver);
478
479 // acknowledgment points to the m_acknowledgment member of txParams, which is
480 // passed as const reference because it must not be modified. Therefore, we
481 // make a copy of the object pointed to by acknowledgment and make changes to
482 // the copy
483 acknowledgment = new WifiDlMuBarBaSequence(*acknowledgment);
484 acknowledgment->stationsReplyingWithNormalAck.clear();
485
486 acknowledgment->stationsReplyingWithBlockAck.emplace(
487 receiver,
489 GetWifiRemoteStationManager()->GetBlockAckTxVector(receiver, txParams.m_txVector),
490 m_mac->GetBaTypeAsOriginator(receiver, tid)});
491 return std::unique_ptr<WifiDlMuBarBaSequence>(acknowledgment);
492 }
493
494 // we get here if this is the first MPDU for this receiver
495 auto htFem = DynamicCast<HtFrameExchangeManager>(m_mac->GetFrameExchangeManager(m_linkId));
496 NS_ASSERT(htFem);
497 if (auto bar = htFem->GetBar(QosUtilsMapTidToAc(tid), tid, receiver);
498 bar || (acknowledgment && (!acknowledgment->stationsReplyingWithNormalAck.empty() ||
499 !acknowledgment->stationsReplyingWithBlockAck.empty())))
500 {
501 // there is a pending BlockAckReq for this receiver or another receiver
502 // was selected for immediate response.
503 // Add this receiver to the list of stations receiving a BlockAckReq.
504 if (acknowledgment)
505 {
506 // txParams.m_acknowledgment points to an existing WifiDlMuBarBaSequence object.
507 // We have to return a copy of this object including the needed changes
508 acknowledgment = new WifiDlMuBarBaSequence(*acknowledgment);
509 }
510 else
511 {
512 // we have to create a new WifiDlMuBarBaSequence object
513 acknowledgment = new WifiDlMuBarBaSequence;
514 }
515
516 NS_LOG_DEBUG("Adding STA " << receiver
517 << " to the list of stations receiving a BlockAckReq");
518 acknowledgment->stationsSendBlockAckReqTo.emplace(
519 receiver,
521 GetWifiRemoteStationManager()->GetBlockAckTxVector(receiver, txParams.m_txVector),
522 m_mac->GetBarTypeAsOriginator(receiver, tid),
523 GetWifiRemoteStationManager()->GetBlockAckTxVector(receiver, txParams.m_txVector),
524 m_mac->GetBaTypeAsOriginator(receiver, tid)});
525
526 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::BLOCK_ACK);
527 return std::unique_ptr<WifiDlMuBarBaSequence>(acknowledgment);
528 }
529
530 // Add the receiver as the station that will immediately reply with a Normal Ack
531 if (acknowledgment)
532 {
533 // txParams.m_acknowledgment points to an existing WifiDlMuBarBaSequence object.
534 // We have to return a copy of this object including the needed changes
535 acknowledgment = new WifiDlMuBarBaSequence(*acknowledgment);
536 }
537 else
538 {
539 // we have to create a new WifiDlMuBarBaSequence object
540 acknowledgment = new WifiDlMuBarBaSequence;
541 }
542
543 NS_LOG_DEBUG("Adding STA " << receiver
544 << " as the station that will immediately reply with a Normal Ack");
545 acknowledgment->stationsReplyingWithNormalAck.emplace(
546 receiver,
548 GetWifiRemoteStationManager()->GetAckTxVector(receiver, txParams.m_txVector)});
549
550 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::NORMAL_ACK);
551 return std::unique_ptr<WifiDlMuBarBaSequence>(acknowledgment);
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 NS_ASSERT(!txParams.m_acknowledgment ||
567
568 WifiDlMuTfMuBar* acknowledgment = nullptr;
569 if (txParams.m_acknowledgment)
570 {
571 acknowledgment = static_cast<WifiDlMuTfMuBar*>(txParams.m_acknowledgment.get());
572 }
573
574 if (txParams.LastAddedIsFirstMpdu(receiver))
575 {
576 // we get here if this is the first MPDU for this receiver.
578 NS_ABORT_MSG_IF(!apMac, "HE APs only can send DL MU PPDUs");
579 uint16_t staId = apMac->GetAssociationId(receiver, m_linkId);
580
582 "QoS data frames only can be aggregated when transmitting a "
583 "DL MU PPDU acknowledged via a MU-BAR sent as SU frame");
584 uint8_t tid = hdr.GetQosTid();
585
586 // Add the receiver to the list of stations that will reply with a Block Ack
587 if (acknowledgment)
588 {
589 // txParams.m_acknowledgment points to an existing WifiDlMuTfMuBar object.
590 // We have to return a copy of this object including the needed changes
591 acknowledgment = new WifiDlMuTfMuBar(*acknowledgment);
592 }
593 else
594 {
595 // we have to create a new WifiDlMuTfMuBar object
596 acknowledgment = new WifiDlMuTfMuBar;
597 }
598
599 // determine the TX vector used to send the BlockAck frame
600 WifiTxVector blockAckTxVector;
601 auto preamble = IsEht(txParams.m_txVector.GetPreambleType()) ? WIFI_PREAMBLE_EHT_TB
603 blockAckTxVector.SetPreambleType(preamble);
604 blockAckTxVector.SetChannelWidth(txParams.m_txVector.GetChannelWidth());
605 // 800ns GI is not allowed for HE TB
606 blockAckTxVector.SetGuardInterval(
607 std::max(txParams.m_txVector.GetGuardInterval(), NanoSeconds(1600)));
608 const auto& userInfo = txParams.m_txVector.GetHeMuUserInfo(staId);
609 blockAckTxVector.SetHeMuUserInfo(
610 staId,
611 {userInfo.ru, std::min(userInfo.mcs, m_maxMcsForBlockAckInTbPpdu), userInfo.nss});
612
613 NS_LOG_DEBUG("Adding STA "
614 << receiver
615 << " to the list of stations that will be solicited by the MU-BAR");
616 Ptr<QosTxop> edca = m_mac->GetQosTxop(QosUtilsMapTidToAc(tid));
617 acknowledgment->stationsReplyingWithBlockAck.emplace(
618 receiver,
619 WifiDlMuTfMuBar::BlockAckInfo{edca->GetBaManager()->GetBlockAckReqHeader(
620 mpdu->GetOriginal()->GetHeader().GetAddr1(),
621 tid),
622 blockAckTxVector,
623 m_mac->GetBaTypeAsOriginator(receiver, tid)});
624
625 acknowledgment->barTypes.push_back(m_mac->GetBarTypeAsOriginator(receiver, tid));
626 acknowledgment->muBarTxVector =
627 GetWifiRemoteStationManager()->GetRtsTxVector(receiver,
628 txParams.m_txVector.GetChannelWidth());
629 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::BLOCK_ACK);
630 return std::unique_ptr<WifiDlMuTfMuBar>(acknowledgment);
631 }
632
633 // an MPDU addressed to the same receiver has been already added
634 NS_ASSERT(acknowledgment);
636 "QoS data frames only can be aggregated when transmitting a DL MU PPDU");
637
638 // no change is needed
639 return nullptr;
640}
641
642std::unique_ptr<WifiAcknowledgment>
644 const WifiTxParameters& txParams)
645{
646 NS_LOG_FUNCTION(this << *mpdu << &txParams);
647 NS_ASSERT(txParams.m_txVector.IsDlMu());
649
650 const WifiMacHeader& hdr = mpdu->GetHeader();
651 Mac48Address receiver = hdr.GetAddr1();
652
653 NS_ASSERT(!txParams.m_acknowledgment ||
655
656 WifiDlMuAggregateTf* acknowledgment = nullptr;
657 if (txParams.m_acknowledgment)
658 {
659 acknowledgment = static_cast<WifiDlMuAggregateTf*>(txParams.m_acknowledgment.get());
660 }
661
662 if (txParams.LastAddedIsFirstMpdu(receiver))
663 {
664 // we get here if this is the first MPDU for this receiver.
666 NS_ABORT_MSG_IF(!apMac, "HE APs only can send DL MU PPDUs");
667 uint16_t staId = apMac->GetAssociationId(receiver, m_linkId);
668
670 "QoS data frames only can be aggregated when transmitting a "
671 "DL MU PPDU acknowledged via a sequence of BAR and BA frames");
672 uint8_t tid = hdr.GetQosTid();
673
674 // Add the receiver to the list of stations that will reply with a Block Ack
675 if (acknowledgment)
676 {
677 // txParams.m_acknowledgment points to an existing WifiDlMuAggregateTf object.
678 // We have to return a copy of this object including the needed changes
679 acknowledgment = new WifiDlMuAggregateTf(*acknowledgment);
680 }
681 else
682 {
683 // we have to create a new WifiDlMuAggregateTf object
684 acknowledgment = new WifiDlMuAggregateTf;
685 }
686
687 // determine the TX vector used to send the BlockAck frame
688 WifiTxVector blockAckTxVector;
689 auto preamble = IsEht(txParams.m_txVector.GetPreambleType()) ? WIFI_PREAMBLE_EHT_TB
691 blockAckTxVector.SetPreambleType(preamble);
692 blockAckTxVector.SetChannelWidth(txParams.m_txVector.GetChannelWidth());
693 // 800ns GI is not allowed for HE TB
694 blockAckTxVector.SetGuardInterval(
695 std::max(txParams.m_txVector.GetGuardInterval(), NanoSeconds(1600)));
696 const auto& userInfo = txParams.m_txVector.GetHeMuUserInfo(staId);
697 blockAckTxVector.SetHeMuUserInfo(
698 staId,
699 {userInfo.ru, std::min(userInfo.mcs, m_maxMcsForBlockAckInTbPpdu), userInfo.nss});
700
701 NS_LOG_DEBUG("Adding STA " << receiver
702 << " to the list of stations that will reply with a Block Ack");
703 Ptr<QosTxop> edca = m_mac->GetQosTxop(QosUtilsMapTidToAc(tid));
704 acknowledgment->stationsReplyingWithBlockAck.emplace(
705 receiver,
709 txParams.m_txVector.GetChannelWidth(),
710 {m_mac->GetBarTypeAsOriginator(receiver, tid)}),
711 edca->GetBaManager()->GetBlockAckReqHeader(
712 mpdu->GetOriginal()->GetHeader().GetAddr1(),
713 tid),
714 blockAckTxVector,
715 m_mac->GetBaTypeAsOriginator(receiver, tid)});
716
717 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::NO_EXPLICIT_ACK);
718 return std::unique_ptr<WifiDlMuAggregateTf>(acknowledgment);
719 }
720
721 // an MPDU addressed to the same receiver has been already added
722 NS_ASSERT(acknowledgment);
724 !hdr.IsQosData(),
725 "QoS data and MU-BAR Trigger frames only can be aggregated when transmitting a DL MU PPDU");
726
727 // no change is needed
728 return nullptr;
729}
730
731std::unique_ptr<WifiAcknowledgment>
733 const WifiTxParameters& txParams)
734{
735 NS_LOG_FUNCTION(this << *mpdu << &txParams);
736 NS_ASSERT(mpdu->GetHeader().IsTrigger());
737
739 NS_ABORT_MSG_IF(!apMac, "HE APs only can send Trigger Frames");
740
741 auto heFem = DynamicCast<HeFrameExchangeManager>(m_mac->GetFrameExchangeManager(m_linkId));
742 NS_ABORT_MSG_IF(!heFem, "HE APs only can send Trigger Frames");
743
744 CtrlTriggerHeader trigger;
745 mpdu->GetPacket()->PeekHeader(trigger);
746
747 if (trigger.IsBasic())
748 {
749 // the only supported ack method for now is through a multi-STA BlockAck frame
750 auto acknowledgment = std::make_unique<WifiUlMuMultiStaBa>();
751
752 for (const auto& userInfo : trigger)
753 {
754 uint16_t aid12 = userInfo.GetAid12();
755
756 if (aid12 == NO_USER_STA_ID)
757 {
758 NS_LOG_INFO("Unallocated RU");
759 continue;
760 }
761 const auto maxAid =
763 NS_ABORT_MSG_IF(aid12 < MIN_AID || aid12 > maxAid,
764 "Allocation of RA-RUs is not supported");
765
766 const auto it = apMac->GetStaList(m_linkId).find(aid12);
767 NS_ASSERT(it != apMac->GetStaList(m_linkId).end());
768 const auto staAddress = it->second;
769
770 // find a TID for which a BA agreement exists with the given originator
771 uint8_t tid = 0;
772 while (tid < 8 && !m_mac->GetBaAgreementEstablishedAsRecipient(staAddress, tid))
773 {
774 tid++;
775 }
776 NS_ASSERT_MSG(tid < 8,
777 "No Block Ack agreement established with originator " << staAddress);
778
779 std::size_t index = acknowledgment->baType.m_bitmapLen.size();
780 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(staAddress, tid),
781 index);
782
783 // we assume the Block Acknowledgment context is used for the multi-STA BlockAck frame
784 // (since it requires the longest TX time due to the presence of a bitmap)
785 acknowledgment->baType.m_bitmapLen.push_back(
786 m_mac->GetBaTypeAsRecipient(staAddress, tid).m_bitmapLen.at(0));
787 }
788
789 uint16_t staId = trigger.begin()->GetAid12();
790 acknowledgment->tbPpduTxVector = trigger.GetHeTbTxVector(staId);
791 acknowledgment->multiStaBaTxVector = GetWifiRemoteStationManager()->GetBlockAckTxVector(
792 apMac->GetStaList(m_linkId).find(staId)->second,
793 acknowledgment->tbPpduTxVector);
794 return acknowledgment;
795 }
796 else if (trigger.IsBsrp())
797 {
798 return std::make_unique<WifiNoAck>();
799 }
800
801 return nullptr;
802}
803
804} // namespace ns3
AttributeValue implementation for Boolean.
Definition boolean.h:26
Headers for BlockAckRequest.
Headers for Trigger frames.
bool IsBasic() const
Check if this is a Basic Trigger frame.
WifiTxVector GetHeTbTxVector(uint16_t staId) const
Get the TX vector that the station with the given STA-ID will use to send the HE TB PPDU solicited by...
bool IsBsrp() const
Check if this is a Buffer Status Report Poll Trigger frame.
ConstIterator begin() const
Get a const iterator pointing to the first User Info field in the list.
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Definition double.h:31
Hold variables of type enum.
Definition enum.h:52
an EUI-48 address
bool IsGroup() const
Smart pointer class similar to boost::intrusive_ptr.
a unique identifier for an interface.
Definition type-id.h:49
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
Hold an unsigned integer type.
Definition uinteger.h:34
WifiAckManager is an abstract base class.
uint8_t m_linkId
ID of the link this Acknowledgment Manager is operating on.
Ptr< WifiMac > m_mac
MAC which is using this Acknowledgment Manager.
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager() const
WifiDefaultAckManager is the default ack manager.
bool IsResponseNeeded(Ptr< const WifiMpdu > mpdu, const WifiTxParameters &txParams) const
Determine whether the (A-)MPDU containing the given MPDU and the MPDUs (if any) included in the given...
static TypeId GetTypeId()
Get the type ID.
virtual std::unique_ptr< WifiAcknowledgment > GetAckInfoIfBarBaSequence(Ptr< const WifiMpdu > mpdu, const WifiTxParameters &txParams)
Compute the information about the acknowledgment of the current multi-user frame (as described by the...
bool m_useExplicitBar
true for sending BARs, false for using Implicit BAR policy
uint8_t m_maxMcsForBlockAckInTbPpdu
Max MCS used to send a BlockAck in a TB PPDU.
double m_baThreshold
Threshold to determine when a BlockAck must be requested.
virtual std::unique_ptr< WifiAcknowledgment > GetAckInfoIfTfMuBar(Ptr< const WifiMpdu > mpdu, const WifiTxParameters &txParams)
Compute the information about the acknowledgment of the current multi-user frame (as described by the...
WifiAcknowledgment::Method m_dlMuAckType
Type of the ack sequence for DL MU PPDUs.
std::unique_ptr< WifiAcknowledgment > TryAggregateMsdu(Ptr< const WifiMpdu > msdu, const WifiTxParameters &txParams) override
Determine the acknowledgment method to use if the given MSDU is aggregated to the current frame.
uint16_t GetMaxDistFromStartingSeq(Ptr< const WifiMpdu > mpdu, const WifiTxParameters &txParams) const
Get the maximum distance between the starting sequence number of the Block Ack agreement which the gi...
bool ExistInflightOnSameLink(Ptr< const WifiMpdu > mpdu) const
std::unique_ptr< WifiAcknowledgment > TryAddMpdu(Ptr< const WifiMpdu > mpdu, const WifiTxParameters &txParams) override
Determine the acknowledgment method to use if the given MPDU is added to the current frame.
virtual std::unique_ptr< WifiAcknowledgment > GetAckInfoIfAggregatedMuBar(Ptr< const WifiMpdu > mpdu, const WifiTxParameters &txParams)
Compute the information about the acknowledgment of the current multi-user frame (as described by the...
virtual std::unique_ptr< WifiAcknowledgment > TryUlMuTransmission(Ptr< const WifiMpdu > mpdu, const WifiTxParameters &txParams)
Calculate the acknowledgment method for the TB PPDUs solicited by the given Trigger Frame.
Implements the IEEE 802.11 MAC header.
uint8_t GetQosTid() const
Return the Traffic ID of a QoS header.
bool IsBlockAckReq() const
Return true if the header is a BlockAckRequest header.
Mac48Address GetAddr1() const
Return the address in the Address 1 field.
bool IsTrigger() const
Return true if the header is a Trigger header.
bool HasData() const
Return true if the header type is DATA and is not DATA_NULL.
bool IsQosData() const
Return true if the Type is DATA and Subtype is one of the possible values for QoS Data.
This class stores the TX parameters (TX vector, protection mechanism, acknowledgment mechanism,...
std::unique_ptr< WifiProtection > m_protection
protection method
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,...
bool LastAddedIsFirstMpdu(Mac48Address receiver) const
Check if the last added MPDU is the first MPDU for the given receiver.
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...
void SetGuardInterval(Time guardInterval)
Sets the guard interval duration (in nanoseconds)
void SetHeMuUserInfo(uint16_t staId, HeMuUserInfo userInfo)
Set the HE MU user-specific transmission information for the given STA-ID.
WifiPreamble GetPreambleType() const
HeMuUserInfo GetHeMuUserInfo(uint16_t staId) const
Get the HE MU user-specific transmission information for the given STA-ID.
void SetChannelWidth(MHz_u channelWidth)
Sets the selected channelWidth.
MHz_u GetChannelWidth() const
Time GetGuardInterval() const
void SetPreambleType(WifiPreamble preamble)
Sets the preamble type.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
#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:75
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition boolean.cc:113
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition boolean.h:70
Ptr< const AttributeChecker > MakeDoubleChecker()
Definition double.h:82
Ptr< const AttributeAccessor > MakeDoubleAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition double.h:32
Ptr< const AttributeAccessor > MakeEnumAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition enum.h:221
Ptr< const AttributeChecker > MakeUintegerChecker()
Definition uinteger.h:85
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition uinteger.h:35
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition abort.h:38
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition abort.h:97
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#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:264
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1405
AcIndex QosUtilsMapTidToAc(uint8_t tid)
Maps TID (Traffic ID) to Access classes.
Definition qos-utils.cc:123
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:156
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:165
@ WIFI_PREAMBLE_EHT_TB
@ WIFI_PREAMBLE_HE_TB
Every class exported by the ns3 library is enclosed in the ns3 namespace.
uint32_t GetMuBarSize(TriggerFrameVariant variant, MHz_u bw, const std::list< BlockAckReqType > &types)
Return the total MU-BAR size (including FCS trailer).
Definition wifi-utils.cc:79
bool IsEht(WifiPreamble preamble)
Return true if a preamble corresponds to an EHT transmission.
Ptr< const AttributeChecker > MakeEnumChecker(T v, std::string n, Ts... args)
Make an EnumChecker pre-configured with a set of allowed values by name.
Definition enum.h:179
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:585
static constexpr uint16_t NO_USER_STA_ID
STA_ID for a RU that is intended for no user (Section 26.11.1 802.11ax-2021)
static constexpr uint16_t SEQNO_SPACE_SIZE
Size of the space of sequence numbers.
std::tuple< WifiContainerQueueType, WifiRcvAddr, Mac48Address, std::optional< uint8_t > > WifiContainerQueueId
Tuple (queue type, receiver address type, Address, TID) identifying a container queue.
bool IsGcr(Ptr< WifiMac > mac, const WifiMacHeader &hdr)
Return whether a given packet is transmitted using the GCR service.
static constexpr uint16_t MAX_AID
The maximum value for the association ID (Sec. 9.4.1.8 of 802.11-2020)
static constexpr uint16_t EHT_MAX_AID
The maximum value for the association ID updated since 802.11be (Sec. 9.4.1.8 of 802....
void SetQosAckPolicy(Mac48Address receiver, uint8_t tid, WifiMacHeader::QosAckPolicy ackPolicy)
Set the QoS Ack policy to use for the MPDUs addressed to the given receiver and belonging to the give...
information related to a BlockAck frame sent by a station
WifiDlMuAggregateTf specifies that a DL MU PPDU made of PSDUs including each a MU-BAR Trigger Frame i...
std::map< Mac48Address, BlockAckInfo > stationsReplyingWithBlockAck
Set of stations replying with a BlockAck frame.
information related to an Ack frame sent by a station
information related to a BlockAck frame sent by a station
information related to a BlockAckReq frame sent to a station
WifiDlMuBarBaSequence specifies that a DL MU PPDU is acknowledged through a sequence of BlockAckReq a...
std::map< Mac48Address, BlockAckReqInfo > stationsSendBlockAckReqTo
Set of stations receiving a BlockAckReq frame and replying with a BlockAck frame.
std::map< Mac48Address, BlockAckInfo > stationsReplyingWithBlockAck
Set of stations replying with a BlockAck frame (no more than one)
std::map< Mac48Address, AckInfo > stationsReplyingWithNormalAck
Set of stations replying with an Ack frame (no more than one)
information related to a BlockAck frame sent by a station
WifiDlMuTfMuBar specifies that a DL MU PPDU is followed after a SIFS duration by a MU-BAR Trigger Fra...
std::list< BlockAckReqType > barTypes
BAR types.
std::map< Mac48Address, BlockAckInfo > stationsReplyingWithBlockAck
Set of stations replying with a BlockAck frame.
WifiTxVector muBarTxVector
TXVECTOR used to transmit the MU-BAR Trigger Frame.
std::map< uint8_t, std::set< uint16_t > > seqNumbers
set of the sequence numbers of the MPDUs added for each TID