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
29
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 const auto& hdr = mpdu->GetHeader();
227
228 if (hdr.IsPsPoll())
229 {
230 NS_ASSERT(!txParams.m_acknowledgment);
231 return std::make_unique<WifiNoAck>();
232 }
233
234 // If the TXVECTOR indicates a DL MU PPDU, call a separate method
235 if (txParams.m_txVector.IsDlMu())
236 {
237 switch (m_dlMuAckType)
238 {
240 return GetAckInfoIfBarBaSequence(mpdu, txParams);
242 return GetAckInfoIfTfMuBar(mpdu, txParams);
244 return GetAckInfoIfAggregatedMuBar(mpdu, txParams);
245 default:
246 NS_ABORT_MSG("Unknown DL acknowledgment method");
247 return nullptr;
248 }
249 }
250
251 Mac48Address receiver = hdr.GetAddr1();
252
253 // Acknowledgment for TB PPDUs
254 if (txParams.m_txVector.IsUlMu())
255 {
256 if (hdr.IsQosData() && !hdr.HasData())
257 {
258 // QoS Null frame
259 std::unique_ptr<WifiAcknowledgment> acknowledgment;
260
261 if (txParams.m_acknowledgment)
262 {
264 acknowledgment = txParams.m_acknowledgment->Copy();
265 }
266 else
267 {
268 acknowledgment = std::make_unique<WifiNoAck>();
269 }
270 acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::NO_ACK);
271 return acknowledgment;
272 }
273
274 if (txParams.m_acknowledgment)
275 {
277 return nullptr;
278 }
279
280 auto acknowledgment = std::make_unique<WifiAckAfterTbPpdu>();
281 if (hdr.IsQosData())
282 {
283 acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::NORMAL_ACK);
284 }
285 return acknowledgment;
286 }
287
288 // if this is a Trigger Frame, call a separate method
289 if (hdr.IsTrigger())
290 {
291 return TryUlMuTransmission(mpdu, txParams);
292 }
293
294 // if the current acknowledgment method (if any) is already BLOCK_ACK, it will not
295 // change by adding an MPDU
296 if (txParams.m_acknowledgment &&
298 {
299 return nullptr;
300 }
301
302 if (receiver.IsGroup())
303 {
304 // if the current acknowledgment method (if any) is already BAR_BLOCK_ACK, it will not
305 // change by adding an MPDU
306 if (txParams.m_acknowledgment &&
308 {
309 return nullptr;
310 }
311 const auto isGcr = IsGcr(m_mac, hdr);
312 NS_ABORT_MSG_IF(!isGcr && !txParams.LastAddedIsFirstMpdu(receiver),
313 "Unicast frames only can be aggregated if GCR is not used");
314 if (auto apMac = DynamicCast<ApWifiMac>(m_mac);
315 isGcr && apMac->GetGcrManager()->GetRetransmissionPolicyFor(hdr) ==
317 {
318 NS_LOG_DEBUG("Request to schedule a GCR Block Ack Request");
319 const auto recipient =
320 apMac->GetGcrManager()->GetIndividuallyAddressedRecipient(receiver);
321 auto acknowledgment = std::make_unique<WifiBarBlockAck>();
322 acknowledgment->blockAckReqTxVector =
323 GetWifiRemoteStationManager()->GetBlockAckTxVector(recipient, txParams.m_txVector);
324 acknowledgment->blockAckTxVector = acknowledgment->blockAckReqTxVector;
325 acknowledgment->barType = BlockAckReqType::GCR;
326 acknowledgment->baType = BlockAckType::GCR;
327 acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::BLOCK_ACK);
328 return acknowledgment;
329 }
330 auto acknowledgment = std::make_unique<WifiNoAck>();
331 if (hdr.IsQosData())
332 {
333 acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::NO_ACK);
334 }
335 return acknowledgment;
336 }
337
338 if ((!hdr.IsQosData() ||
339 !m_mac->GetBaAgreementEstablishedAsOriginator(receiver, hdr.GetQosTid())) &&
340 !hdr.IsBlockAckReq())
341 {
343 "Non-QoS data frame or Block Ack agreement not established, request Normal Ack");
344 auto acknowledgment = std::make_unique<WifiNormalAck>();
345 acknowledgment->ackTxVector =
346 GetWifiRemoteStationManager()->GetAckTxVector(receiver, txParams.m_txVector);
347 if (hdr.IsQosData())
348 {
349 acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::NORMAL_ACK);
350 }
351 return acknowledgment;
352 }
353
354 // we get here if mpdu is a QoS data frame related to an established Block Ack agreement
355 // or mpdu is a BlockAckReq frame
356 if (!hdr.IsBlockAckReq() && !IsResponseNeeded(mpdu, txParams))
357 {
358 NS_LOG_DEBUG("A response is not needed: no ack for now, use Block Ack policy");
359 if (txParams.m_acknowledgment &&
360 txParams.m_acknowledgment->method == WifiAcknowledgment::NONE)
361 {
362 // no change if the ack method is already NONE
363 return nullptr;
364 }
365
366 auto acknowledgment = std::make_unique<WifiNoAck>();
367 if (hdr.IsQosData())
368 {
369 acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::BLOCK_ACK);
370 }
371 return acknowledgment;
372 }
373
374 // we get here if a response is needed
375 uint8_t tid = GetTid(mpdu->GetPacket(), hdr);
376 if (!hdr.IsBlockAckReq() && txParams.LastAddedIsFirstMpdu(receiver) &&
378 {
379 NS_LOG_DEBUG("Sending a single MPDU, no previous frame to ack: request Normal Ack");
380 auto acknowledgment = std::make_unique<WifiNormalAck>();
381 acknowledgment->ackTxVector =
382 GetWifiRemoteStationManager()->GetAckTxVector(receiver, txParams.m_txVector);
383 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::NORMAL_ACK);
384 return acknowledgment;
385 }
386
387 // we get here if multiple MPDUs are being/have been sent
388 if (!hdr.IsBlockAckReq() && (txParams.LastAddedIsFirstMpdu(receiver) || m_useExplicitBar))
389 {
390 // in case of single MPDU, there are previous unacknowledged frames, thus
391 // we cannot use Implicit Block Ack Request policy, otherwise we get a
392 // normal ack as response
393 NS_LOG_DEBUG("Request to schedule a Block Ack Request");
394
395 auto acknowledgment = std::make_unique<WifiBarBlockAck>();
396 acknowledgment->blockAckReqTxVector =
397 GetWifiRemoteStationManager()->GetBlockAckTxVector(receiver, txParams.m_txVector);
398 acknowledgment->blockAckTxVector = acknowledgment->blockAckReqTxVector;
399 acknowledgment->barType = m_mac->GetBarTypeAsOriginator(receiver, tid);
400 acknowledgment->baType = m_mac->GetBaTypeAsOriginator(receiver, tid);
401 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::BLOCK_ACK);
402 return acknowledgment;
403 }
404
405 if (hdr.IsBlockAckReq())
406 {
407 CtrlBAckRequestHeader baReqHdr;
408 mpdu->GetPacket()->PeekHeader(baReqHdr);
409 if (baReqHdr.IsGcr())
410 {
411 NS_LOG_DEBUG("GCR Block Ack Req, request GCR Block Ack");
412 auto acknowledgment = std::make_unique<WifiBlockAck>();
413 acknowledgment->blockAckTxVector =
414 GetWifiRemoteStationManager()->GetBlockAckTxVector(receiver, txParams.m_txVector);
415 acknowledgment->baType = BlockAckType::GCR;
416 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::NORMAL_ACK);
417 return acknowledgment;
418 }
419 }
420
422 "A-MPDU using Implicit Block Ack Request policy or BlockAckReq, request Block Ack");
423 auto acknowledgment = std::make_unique<WifiBlockAck>();
424 acknowledgment->blockAckTxVector =
425 GetWifiRemoteStationManager()->GetBlockAckTxVector(receiver, txParams.m_txVector);
426 acknowledgment->baType = m_mac->GetBaTypeAsOriginator(receiver, tid);
427 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::NORMAL_ACK);
428 return acknowledgment;
429}
430
431std::unique_ptr<WifiAcknowledgment>
433{
434 NS_LOG_FUNCTION(this << *msdu << &txParams);
435
436 // Aggregating an MSDU does not change the acknowledgment method
437 return nullptr;
438}
439
440std::unique_ptr<WifiAcknowledgment>
442 const WifiTxParameters& txParams)
443{
444 NS_LOG_FUNCTION(this << *mpdu << &txParams);
445 NS_ASSERT(txParams.m_txVector.IsDlMu());
447
448 const WifiMacHeader& hdr = mpdu->GetHeader();
449 Mac48Address receiver = hdr.GetAddr1();
450
452 "QoS data frames only can be aggregated when transmitting a "
453 "DL MU PPDU acknowledged via a sequence of BAR and BA frames");
454 uint8_t tid = hdr.GetQosTid();
455 Ptr<QosTxop> edca = m_mac->GetQosTxop(QosUtilsMapTidToAc(tid));
456
457 NS_ASSERT(!txParams.m_acknowledgment ||
459
460 WifiDlMuBarBaSequence* acknowledgment = nullptr;
461 if (txParams.m_acknowledgment)
462 {
463 acknowledgment = static_cast<WifiDlMuBarBaSequence*>(txParams.m_acknowledgment.get());
464 }
465
466 if (!txParams.LastAddedIsFirstMpdu(receiver))
467 {
468 // an MPDU addressed to the same receiver has been already added
469 NS_ASSERT(acknowledgment);
470
471 if (acknowledgment->stationsSendBlockAckReqTo.contains(receiver) ||
472 acknowledgment->stationsReplyingWithBlockAck.contains(receiver))
473 {
474 // the receiver either is already listed among the stations that will
475 // receive a BlockAckReq frame or is the station that will immediately
476 // respond with a BlockAck frame, hence no change is needed
477 return nullptr;
478 }
479
480 // the receiver was scheduled for responding immediately with a Normal Ack.
481 // Given that we are adding an MPDU, the receiver must be scheduled for
482 // responding immediately with a Block Ack
483 NS_ASSERT(acknowledgment->stationsReplyingWithNormalAck.size() == 1 &&
484 acknowledgment->stationsReplyingWithNormalAck.begin()->first == receiver);
485
486 // acknowledgment points to the m_acknowledgment member of txParams, which is
487 // passed as const reference because it must not be modified. Therefore, we
488 // make a copy of the object pointed to by acknowledgment and make changes to
489 // the copy
490 acknowledgment = new WifiDlMuBarBaSequence(*acknowledgment);
491 acknowledgment->stationsReplyingWithNormalAck.clear();
492
493 acknowledgment->stationsReplyingWithBlockAck.emplace(
494 receiver,
496 GetWifiRemoteStationManager()->GetBlockAckTxVector(receiver, txParams.m_txVector),
497 m_mac->GetBaTypeAsOriginator(receiver, tid)});
498 return std::unique_ptr<WifiDlMuBarBaSequence>(acknowledgment);
499 }
500
501 // we get here if this is the first MPDU for this receiver
502 auto htFem = DynamicCast<HtFrameExchangeManager>(m_mac->GetFrameExchangeManager(m_linkId));
503 NS_ASSERT(htFem);
504 if (auto bar = htFem->GetBar(QosUtilsMapTidToAc(tid), tid, receiver);
505 bar || (acknowledgment && (!acknowledgment->stationsReplyingWithNormalAck.empty() ||
506 !acknowledgment->stationsReplyingWithBlockAck.empty())))
507 {
508 // there is a pending BlockAckReq for this receiver or another receiver
509 // was selected for immediate response.
510 // Add this receiver to the list of stations receiving a BlockAckReq.
511 if (acknowledgment)
512 {
513 // txParams.m_acknowledgment points to an existing WifiDlMuBarBaSequence object.
514 // We have to return a copy of this object including the needed changes
515 acknowledgment = new WifiDlMuBarBaSequence(*acknowledgment);
516 }
517 else
518 {
519 // we have to create a new WifiDlMuBarBaSequence object
520 acknowledgment = new WifiDlMuBarBaSequence;
521 }
522
523 NS_LOG_DEBUG("Adding STA " << receiver
524 << " to the list of stations receiving a BlockAckReq");
525 acknowledgment->stationsSendBlockAckReqTo.emplace(
526 receiver,
528 GetWifiRemoteStationManager()->GetBlockAckTxVector(receiver, txParams.m_txVector),
529 m_mac->GetBarTypeAsOriginator(receiver, tid),
530 GetWifiRemoteStationManager()->GetBlockAckTxVector(receiver, txParams.m_txVector),
531 m_mac->GetBaTypeAsOriginator(receiver, tid)});
532
533 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::BLOCK_ACK);
534 return std::unique_ptr<WifiDlMuBarBaSequence>(acknowledgment);
535 }
536
537 // Add the receiver as the station that will immediately reply with a Normal Ack
538 if (acknowledgment)
539 {
540 // txParams.m_acknowledgment points to an existing WifiDlMuBarBaSequence object.
541 // We have to return a copy of this object including the needed changes
542 acknowledgment = new WifiDlMuBarBaSequence(*acknowledgment);
543 }
544 else
545 {
546 // we have to create a new WifiDlMuBarBaSequence object
547 acknowledgment = new WifiDlMuBarBaSequence;
548 }
549
550 NS_LOG_DEBUG("Adding STA " << receiver
551 << " as the station that will immediately reply with a Normal Ack");
552 acknowledgment->stationsReplyingWithNormalAck.emplace(
553 receiver,
555 GetWifiRemoteStationManager()->GetAckTxVector(receiver, txParams.m_txVector)});
556
557 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::NORMAL_ACK);
558 return std::unique_ptr<WifiDlMuBarBaSequence>(acknowledgment);
559}
560
561std::unique_ptr<WifiAcknowledgment>
563 const WifiTxParameters& txParams)
564{
565 NS_LOG_FUNCTION(this << *mpdu << &txParams);
566 NS_ASSERT(txParams.m_txVector.IsDlMu());
568
569 const WifiMacHeader& hdr = mpdu->GetHeader();
570 Mac48Address receiver = hdr.GetAddr1();
571
572 NS_ASSERT(!txParams.m_acknowledgment ||
574
575 WifiDlMuTfMuBar* acknowledgment = nullptr;
576 if (txParams.m_acknowledgment)
577 {
578 acknowledgment = static_cast<WifiDlMuTfMuBar*>(txParams.m_acknowledgment.get());
579 }
580
581 if (txParams.LastAddedIsFirstMpdu(receiver))
582 {
583 // we get here if this is the first MPDU for this receiver.
585 NS_ABORT_MSG_IF(!apMac, "HE APs only can send DL MU PPDUs");
586 uint16_t staId = apMac->GetAssociationId(receiver, m_linkId);
587
589 "QoS data frames only can be aggregated when transmitting a "
590 "DL MU PPDU acknowledged via a MU-BAR sent as SU frame");
591 uint8_t tid = hdr.GetQosTid();
592
593 // Add the receiver to the list of stations that will reply with a Block Ack
594 if (acknowledgment)
595 {
596 // txParams.m_acknowledgment points to an existing WifiDlMuTfMuBar object.
597 // We have to return a copy of this object including the needed changes
598 acknowledgment = new WifiDlMuTfMuBar(*acknowledgment);
599 }
600 else
601 {
602 // we have to create a new WifiDlMuTfMuBar object
603 acknowledgment = new WifiDlMuTfMuBar;
604 }
605
606 // determine the TX vector used to send the BlockAck frame
607 WifiTxVector blockAckTxVector;
608 auto preamble = IsEht(txParams.m_txVector.GetPreambleType()) ? WIFI_PREAMBLE_EHT_TB
610 blockAckTxVector.SetPreambleType(preamble);
611 blockAckTxVector.SetChannelWidth(txParams.m_txVector.GetChannelWidth());
612 // 800ns GI is not allowed for HE TB
613 blockAckTxVector.SetGuardInterval(
614 std::max(txParams.m_txVector.GetGuardInterval(), NanoSeconds(1600)));
615 const auto& userInfo = txParams.m_txVector.GetHeMuUserInfo(staId);
616 blockAckTxVector.SetHeMuUserInfo(
617 staId,
618 {userInfo.ru, std::min(userInfo.mcs, m_maxMcsForBlockAckInTbPpdu), userInfo.nss});
619
620 NS_LOG_DEBUG("Adding STA "
621 << receiver
622 << " to the list of stations that will be solicited by the MU-BAR");
623 Ptr<QosTxop> edca = m_mac->GetQosTxop(QosUtilsMapTidToAc(tid));
624 acknowledgment->stationsReplyingWithBlockAck.emplace(
625 receiver,
626 WifiDlMuTfMuBar::BlockAckInfo{edca->GetBaManager()->GetBlockAckReqHeader(
627 mpdu->GetOriginal()->GetHeader().GetAddr1(),
628 tid),
629 blockAckTxVector,
630 m_mac->GetBaTypeAsOriginator(receiver, tid)});
631
632 acknowledgment->barTypes.push_back(m_mac->GetBarTypeAsOriginator(receiver, tid));
633 acknowledgment->muBarTxVector =
634 GetWifiRemoteStationManager()->GetRtsTxVector(receiver,
635 txParams.m_txVector.GetChannelWidth());
636 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::BLOCK_ACK);
637 return std::unique_ptr<WifiDlMuTfMuBar>(acknowledgment);
638 }
639
640 // an MPDU addressed to the same receiver has been already added
641 NS_ASSERT(acknowledgment);
643 "QoS data frames only can be aggregated when transmitting a DL MU PPDU");
644
645 // no change is needed
646 return nullptr;
647}
648
649std::unique_ptr<WifiAcknowledgment>
651 const WifiTxParameters& txParams)
652{
653 NS_LOG_FUNCTION(this << *mpdu << &txParams);
654 NS_ASSERT(txParams.m_txVector.IsDlMu());
656
657 const WifiMacHeader& hdr = mpdu->GetHeader();
658 Mac48Address receiver = hdr.GetAddr1();
659
660 NS_ASSERT(!txParams.m_acknowledgment ||
662
663 WifiDlMuAggregateTf* acknowledgment = nullptr;
664 if (txParams.m_acknowledgment)
665 {
666 acknowledgment = static_cast<WifiDlMuAggregateTf*>(txParams.m_acknowledgment.get());
667 }
668
669 if (txParams.LastAddedIsFirstMpdu(receiver))
670 {
671 // we get here if this is the first MPDU for this receiver.
673 NS_ABORT_MSG_IF(!apMac, "HE APs only can send DL MU PPDUs");
674 uint16_t staId = apMac->GetAssociationId(receiver, m_linkId);
675
677 "QoS data frames only can be aggregated when transmitting a "
678 "DL MU PPDU acknowledged via a sequence of BAR and BA frames");
679 uint8_t tid = hdr.GetQosTid();
680
681 // Add the receiver to the list of stations that will reply with a Block Ack
682 if (acknowledgment)
683 {
684 // txParams.m_acknowledgment points to an existing WifiDlMuAggregateTf object.
685 // We have to return a copy of this object including the needed changes
686 acknowledgment = new WifiDlMuAggregateTf(*acknowledgment);
687 }
688 else
689 {
690 // we have to create a new WifiDlMuAggregateTf object
691 acknowledgment = new WifiDlMuAggregateTf;
692 }
693
694 // determine the TX vector used to send the BlockAck frame
695 WifiTxVector blockAckTxVector;
696 auto preamble = IsEht(txParams.m_txVector.GetPreambleType()) ? WIFI_PREAMBLE_EHT_TB
698 blockAckTxVector.SetPreambleType(preamble);
699 blockAckTxVector.SetChannelWidth(txParams.m_txVector.GetChannelWidth());
700 // 800ns GI is not allowed for HE TB
701 blockAckTxVector.SetGuardInterval(
702 std::max(txParams.m_txVector.GetGuardInterval(), NanoSeconds(1600)));
703 const auto& userInfo = txParams.m_txVector.GetHeMuUserInfo(staId);
704 blockAckTxVector.SetHeMuUserInfo(
705 staId,
706 {userInfo.ru, std::min(userInfo.mcs, m_maxMcsForBlockAckInTbPpdu), userInfo.nss});
707
708 NS_LOG_DEBUG("Adding STA " << receiver
709 << " to the list of stations that will reply with a Block Ack");
710 Ptr<QosTxop> edca = m_mac->GetQosTxop(QosUtilsMapTidToAc(tid));
711 acknowledgment->stationsReplyingWithBlockAck.emplace(
712 receiver,
716 txParams.m_txVector.GetChannelWidth(),
717 {m_mac->GetBarTypeAsOriginator(receiver, tid)}),
718 edca->GetBaManager()->GetBlockAckReqHeader(
719 mpdu->GetOriginal()->GetHeader().GetAddr1(),
720 tid),
721 blockAckTxVector,
722 m_mac->GetBaTypeAsOriginator(receiver, tid)});
723
724 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::NO_EXPLICIT_ACK);
725 return std::unique_ptr<WifiDlMuAggregateTf>(acknowledgment);
726 }
727
728 // an MPDU addressed to the same receiver has been already added
729 NS_ASSERT(acknowledgment);
731 !hdr.IsQosData(),
732 "QoS data and MU-BAR Trigger frames only can be aggregated when transmitting a DL MU PPDU");
733
734 // no change is needed
735 return nullptr;
736}
737
738std::unique_ptr<WifiAcknowledgment>
740 const WifiTxParameters& txParams)
741{
742 NS_LOG_FUNCTION(this << *mpdu << &txParams);
743 NS_ASSERT(mpdu->GetHeader().IsTrigger());
744
746 NS_ABORT_MSG_IF(!apMac, "HE APs only can send Trigger Frames");
747
748 auto heFem = DynamicCast<HeFrameExchangeManager>(m_mac->GetFrameExchangeManager(m_linkId));
749 NS_ABORT_MSG_IF(!heFem, "HE APs only can send Trigger Frames");
750
751 CtrlTriggerHeader trigger;
752 mpdu->GetPacket()->PeekHeader(trigger);
753
754 if (trigger.IsBasic())
755 {
756 // the only supported ack method for now is through a multi-STA BlockAck frame
757 auto acknowledgment = std::make_unique<WifiUlMuMultiStaBa>();
758
759 for (const auto& userInfo : trigger)
760 {
761 uint16_t aid12 = userInfo.GetAid12();
762
763 if (aid12 == NO_USER_STA_ID)
764 {
765 NS_LOG_INFO("Unallocated RU");
766 continue;
767 }
768 const auto maxAid =
770 NS_ABORT_MSG_IF(aid12 < MIN_AID || aid12 > maxAid,
771 "Allocation of RA-RUs is not supported");
772
773 const auto it = apMac->GetStaList(m_linkId).find(aid12);
774 NS_ASSERT(it != apMac->GetStaList(m_linkId).end());
775 const auto staAddress = it->second;
776
777 // find a TID for which a BA agreement exists with the given originator
778 uint8_t tid = 0;
779 while (tid < 8 && !m_mac->GetBaAgreementEstablishedAsRecipient(staAddress, tid))
780 {
781 tid++;
782 }
783 NS_ASSERT_MSG(tid < 8,
784 "No Block Ack agreement established with originator " << staAddress);
785
786 std::size_t index = acknowledgment->baType.m_bitmapLen.size();
787 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(staAddress, tid),
788 index);
789
790 // we assume the Block Acknowledgment context is used for the multi-STA BlockAck frame
791 // (since it requires the longest TX time due to the presence of a bitmap)
792 acknowledgment->baType.m_bitmapLen.push_back(
793 m_mac->GetBaTypeAsRecipient(staAddress, tid).m_bitmapLen.at(0));
794 }
795
796 uint16_t staId = trigger.begin()->GetAid12();
797 acknowledgment->tbPpduTxVector = trigger.GetHeTbTxVector(staId);
798 acknowledgment->multiStaBaTxVector = GetWifiRemoteStationManager()->GetBlockAckTxVector(
799 apMac->GetStaList(m_linkId).find(staId)->second,
800 acknowledgment->tbPpduTxVector);
801 return acknowledgment;
802 }
803 else if (trigger.IsBsrp())
804 {
805 return std::make_unique<WifiNoAck>();
806 }
807
808 return nullptr;
809}
810
811} // 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.
bool IsBsrp() const
Check if this is a Buffer Status Report Poll Trigger frame.
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.
Definition ptr.h:70
a unique identifier for an interface.
Definition type-id.h:50
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:999
Hold an unsigned integer type.
Definition uinteger.h:34
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.
Mac48Address GetAddr1() const
Return the address in the Address 1 field.
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:223
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:194
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:260
#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:267
#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:1324
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:181
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:605
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