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 = WifiContainerQueueId(WIFI_QOSDATA_QUEUE, WIFI_UNICAST, origReceiver, tid);
156 edca->GetWifiMacQueue()->GetNPackets(queueId) -
157 edca->GetBaManager()->GetNBufferedPackets(origReceiver, tid) - seqNumbers.size() <
158 1)
159 {
160 return true;
161 }
162 // * the block ack TX window cannot advance because all the MPDUs in the TX window other than
163 // those being transmitted have been already acknowledged
164 if (m_mac->GetBaAgreementEstablishedAsOriginator(origReceiver, tid)
165 ->get()
166 .AllAckedMpdusInTxWindow(seqNumbers))
167 {
168 return true;
169 }
170
171 // * this is the initial frame of a transmission opportunity and it is not
172 // protected by RTS/CTS (see Annex G.3 of IEEE 802.11-2016)
173 if (edca->GetTxopLimit(m_linkId).IsStrictlyPositive() &&
174 edca->GetRemainingTxop(m_linkId) == edca->GetTxopLimit(m_linkId) &&
175 !(txParams.m_protection && txParams.m_protection->method == WifiProtection::RTS_CTS))
176 {
177 return true;
178 }
179
180 return false;
181}
182
183bool
185{
186 NS_ASSERT(mpdu->GetHeader().IsQosData());
187 auto tid = mpdu->GetHeader().GetQosTid();
188 NS_ASSERT(mpdu->IsQueued());
189 auto queue = m_mac->GetTxopQueue(mpdu->GetQueueAc());
190 auto origReceiver = mpdu->GetOriginal()->GetHeader().GetAddr1();
191 auto agreement = m_mac->GetBaAgreementEstablishedAsOriginator(origReceiver, tid);
192 NS_ASSERT(agreement);
193 auto mpduDist = agreement->get().GetDistance(mpdu->GetHeader().GetSequenceNumber());
194
195 Ptr<WifiMpdu> item = queue->PeekByTidAndAddress(tid, origReceiver);
196
197 while (item)
198 {
199 auto itemDist = agreement->get().GetDistance(item->GetHeader().GetSequenceNumber());
200 if (itemDist == mpduDist)
201 {
202 NS_LOG_DEBUG("No previous MPDU in-flight on the same link");
203 return false;
204 }
205 NS_ABORT_MSG_IF(itemDist > mpduDist,
206 "While searching for given MPDU ("
207 << *mpdu << "), found first another one (" << *item
208 << ") with higher sequence number");
209 if (auto linkIds = item->GetInFlightLinkIds(); linkIds.contains(m_linkId))
210 {
211 NS_LOG_DEBUG("Found MPDU inflight on the same link");
212 return true;
213 }
214 item = queue->PeekByTidAndAddress(tid, origReceiver, item);
215 }
216 NS_ABORT_MSG("Should not get here");
217 return false;
218}
219
220std::unique_ptr<WifiAcknowledgment>
222{
223 NS_LOG_FUNCTION(this << *mpdu << &txParams);
224
225 // If the TXVECTOR indicates a DL MU PPDU, call a separate method
226 if (txParams.m_txVector.IsDlMu())
227 {
228 switch (m_dlMuAckType)
229 {
231 return GetAckInfoIfBarBaSequence(mpdu, txParams);
233 return GetAckInfoIfTfMuBar(mpdu, txParams);
235 return GetAckInfoIfAggregatedMuBar(mpdu, txParams);
236 default:
237 NS_ABORT_MSG("Unknown DL acknowledgment method");
238 return nullptr;
239 }
240 }
241
242 const WifiMacHeader& hdr = mpdu->GetHeader();
243 Mac48Address receiver = hdr.GetAddr1();
244
245 // Acknowledgment for TB PPDUs
246 if (txParams.m_txVector.IsUlMu())
247 {
248 if (hdr.IsQosData() && !hdr.HasData())
249 {
250 // QoS Null frame
251 std::unique_ptr<WifiAcknowledgment> acknowledgment;
252
253 if (txParams.m_acknowledgment)
254 {
256 acknowledgment = txParams.m_acknowledgment->Copy();
257 }
258 else
259 {
260 acknowledgment = std::make_unique<WifiNoAck>();
261 }
262 acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::NO_ACK);
263 return acknowledgment;
264 }
265
266 if (txParams.m_acknowledgment)
267 {
269 return nullptr;
270 }
271
272 auto acknowledgment = std::make_unique<WifiAckAfterTbPpdu>();
273 if (hdr.IsQosData())
274 {
275 acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::NORMAL_ACK);
276 }
277 return acknowledgment;
278 }
279
280 // if this is a Trigger Frame, call a separate method
281 if (hdr.IsTrigger())
282 {
283 return TryUlMuTransmission(mpdu, txParams);
284 }
285
286 // if the current acknowledgment method (if any) is already BLOCK_ACK, it will not
287 // change by adding an MPDU
288 if (txParams.m_acknowledgment &&
290 {
291 return nullptr;
292 }
293
294 if (receiver.IsGroup())
295 {
296 // if the current acknowledgment method (if any) is already BAR_BLOCK_ACK, it will not
297 // change by adding an MPDU
298 if (txParams.m_acknowledgment &&
300 {
301 return nullptr;
302 }
303 const auto isGcr = IsGcr(m_mac, hdr);
304 NS_ABORT_MSG_IF(!isGcr && !txParams.LastAddedIsFirstMpdu(receiver),
305 "Unicast frames only can be aggregated if GCR is not used");
306 if (auto apMac = DynamicCast<ApWifiMac>(m_mac);
307 isGcr && apMac->GetGcrManager()->GetRetransmissionPolicyFor(hdr) ==
309 {
310 NS_LOG_DEBUG("Request to schedule a GCR Block Ack Request");
311 const auto recipient =
312 apMac->GetGcrManager()->GetIndividuallyAddressedRecipient(receiver);
313 auto acknowledgment = std::make_unique<WifiBarBlockAck>();
314 acknowledgment->blockAckReqTxVector =
315 GetWifiRemoteStationManager()->GetBlockAckTxVector(recipient, txParams.m_txVector);
316 acknowledgment->blockAckTxVector = acknowledgment->blockAckReqTxVector;
317 acknowledgment->barType = BlockAckReqType::GCR;
318 acknowledgment->baType = BlockAckType::GCR;
319 acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::BLOCK_ACK);
320 return acknowledgment;
321 }
322 auto acknowledgment = std::make_unique<WifiNoAck>();
323 if (hdr.IsQosData())
324 {
325 acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::NO_ACK);
326 }
327 return acknowledgment;
328 }
329
330 if ((!hdr.IsQosData() ||
331 !m_mac->GetBaAgreementEstablishedAsOriginator(receiver, hdr.GetQosTid())) &&
332 !hdr.IsBlockAckReq())
333 {
335 "Non-QoS data frame or Block Ack agreement not established, request Normal Ack");
336 auto acknowledgment = std::make_unique<WifiNormalAck>();
337 acknowledgment->ackTxVector =
338 GetWifiRemoteStationManager()->GetAckTxVector(receiver, txParams.m_txVector);
339 if (hdr.IsQosData())
340 {
341 acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::NORMAL_ACK);
342 }
343 return acknowledgment;
344 }
345
346 // we get here if mpdu is a QoS data frame related to an established Block Ack agreement
347 // or mpdu is a BlockAckReq frame
348 if (!hdr.IsBlockAckReq() && !IsResponseNeeded(mpdu, txParams))
349 {
350 NS_LOG_DEBUG("A response is not needed: no ack for now, use Block Ack policy");
351 if (txParams.m_acknowledgment &&
352 txParams.m_acknowledgment->method == WifiAcknowledgment::NONE)
353 {
354 // no change if the ack method is already NONE
355 return nullptr;
356 }
357
358 auto acknowledgment = std::make_unique<WifiNoAck>();
359 if (hdr.IsQosData())
360 {
361 acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::BLOCK_ACK);
362 }
363 return acknowledgment;
364 }
365
366 // we get here if a response is needed
367 uint8_t tid = GetTid(mpdu->GetPacket(), hdr);
368 if (!hdr.IsBlockAckReq() && txParams.LastAddedIsFirstMpdu(receiver) &&
370 {
371 NS_LOG_DEBUG("Sending a single MPDU, no previous frame to ack: request Normal Ack");
372 auto acknowledgment = std::make_unique<WifiNormalAck>();
373 acknowledgment->ackTxVector =
374 GetWifiRemoteStationManager()->GetAckTxVector(receiver, txParams.m_txVector);
375 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::NORMAL_ACK);
376 return acknowledgment;
377 }
378
379 // we get here if multiple MPDUs are being/have been sent
380 if (!hdr.IsBlockAckReq() && (txParams.LastAddedIsFirstMpdu(receiver) || m_useExplicitBar))
381 {
382 // in case of single MPDU, there are previous unacknowledged frames, thus
383 // we cannot use Implicit Block Ack Request policy, otherwise we get a
384 // normal ack as response
385 NS_LOG_DEBUG("Request to schedule a Block Ack Request");
386
387 auto acknowledgment = std::make_unique<WifiBarBlockAck>();
388 acknowledgment->blockAckReqTxVector =
389 GetWifiRemoteStationManager()->GetBlockAckTxVector(receiver, txParams.m_txVector);
390 acknowledgment->blockAckTxVector = acknowledgment->blockAckReqTxVector;
391 acknowledgment->barType = m_mac->GetBarTypeAsOriginator(receiver, tid);
392 acknowledgment->baType = m_mac->GetBaTypeAsOriginator(receiver, tid);
393 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::BLOCK_ACK);
394 return acknowledgment;
395 }
396
397 if (hdr.IsBlockAckReq())
398 {
399 CtrlBAckRequestHeader baReqHdr;
400 mpdu->GetPacket()->PeekHeader(baReqHdr);
401 if (baReqHdr.IsGcr())
402 {
403 NS_LOG_DEBUG("GCR Block Ack Req, request GCR Block Ack");
404 auto acknowledgment = std::make_unique<WifiBlockAck>();
405 acknowledgment->blockAckTxVector =
406 GetWifiRemoteStationManager()->GetBlockAckTxVector(receiver, txParams.m_txVector);
407 acknowledgment->baType = BlockAckType::GCR;
408 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::NORMAL_ACK);
409 return acknowledgment;
410 }
411 }
412
414 "A-MPDU using Implicit Block Ack Request policy or BlockAckReq, request Block Ack");
415 auto acknowledgment = std::make_unique<WifiBlockAck>();
416 acknowledgment->blockAckTxVector =
417 GetWifiRemoteStationManager()->GetBlockAckTxVector(receiver, txParams.m_txVector);
418 acknowledgment->baType = m_mac->GetBaTypeAsOriginator(receiver, tid);
419 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::NORMAL_ACK);
420 return acknowledgment;
421}
422
423std::unique_ptr<WifiAcknowledgment>
425{
426 NS_LOG_FUNCTION(this << *msdu << &txParams);
427
428 // Aggregating an MSDU does not change the acknowledgment method
429 return nullptr;
430}
431
432std::unique_ptr<WifiAcknowledgment>
434 const WifiTxParameters& txParams)
435{
436 NS_LOG_FUNCTION(this << *mpdu << &txParams);
437 NS_ASSERT(txParams.m_txVector.IsDlMu());
439
440 const WifiMacHeader& hdr = mpdu->GetHeader();
441 Mac48Address receiver = hdr.GetAddr1();
442
444 "QoS data frames only can be aggregated when transmitting a "
445 "DL MU PPDU acknowledged via a sequence of BAR and BA frames");
446 uint8_t tid = hdr.GetQosTid();
447 Ptr<QosTxop> edca = m_mac->GetQosTxop(QosUtilsMapTidToAc(tid));
448
449 NS_ASSERT(!txParams.m_acknowledgment ||
451
452 WifiDlMuBarBaSequence* acknowledgment = nullptr;
453 if (txParams.m_acknowledgment)
454 {
455 acknowledgment = static_cast<WifiDlMuBarBaSequence*>(txParams.m_acknowledgment.get());
456 }
457
458 if (!txParams.LastAddedIsFirstMpdu(receiver))
459 {
460 // an MPDU addressed to the same receiver has been already added
461 NS_ASSERT(acknowledgment);
462
463 if (acknowledgment->stationsSendBlockAckReqTo.contains(receiver) ||
464 acknowledgment->stationsReplyingWithBlockAck.contains(receiver))
465 {
466 // the receiver either is already listed among the stations that will
467 // receive a BlockAckReq frame or is the station that will immediately
468 // respond with a BlockAck frame, hence no change is needed
469 return nullptr;
470 }
471
472 // the receiver was scheduled for responding immediately with a Normal Ack.
473 // Given that we are adding an MPDU, the receiver must be scheduled for
474 // responding immediately with a Block Ack
475 NS_ASSERT(acknowledgment->stationsReplyingWithNormalAck.size() == 1 &&
476 acknowledgment->stationsReplyingWithNormalAck.begin()->first == receiver);
477
478 // acknowledgment points to the m_acknowledgment member of txParams, which is
479 // passed as const reference because it must not be modified. Therefore, we
480 // make a copy of the object pointed to by acknowledgment and make changes to
481 // the copy
482 acknowledgment = new WifiDlMuBarBaSequence(*acknowledgment);
483 acknowledgment->stationsReplyingWithNormalAck.clear();
484
485 acknowledgment->stationsReplyingWithBlockAck.emplace(
486 receiver,
488 GetWifiRemoteStationManager()->GetBlockAckTxVector(receiver, txParams.m_txVector),
489 m_mac->GetBaTypeAsOriginator(receiver, tid)});
490 return std::unique_ptr<WifiDlMuBarBaSequence>(acknowledgment);
491 }
492
493 // we get here if this is the first MPDU for this receiver
494 auto htFem = DynamicCast<HtFrameExchangeManager>(m_mac->GetFrameExchangeManager(m_linkId));
495 NS_ASSERT(htFem);
496 if (auto bar = htFem->GetBar(QosUtilsMapTidToAc(tid), tid, receiver);
497 bar || (acknowledgment && (!acknowledgment->stationsReplyingWithNormalAck.empty() ||
498 !acknowledgment->stationsReplyingWithBlockAck.empty())))
499 {
500 // there is a pending BlockAckReq for this receiver or another receiver
501 // was selected for immediate response.
502 // Add this receiver to the list of stations receiving a BlockAckReq.
503 if (acknowledgment)
504 {
505 // txParams.m_acknowledgment points to an existing WifiDlMuBarBaSequence object.
506 // We have to return a copy of this object including the needed changes
507 acknowledgment = new WifiDlMuBarBaSequence(*acknowledgment);
508 }
509 else
510 {
511 // we have to create a new WifiDlMuBarBaSequence object
512 acknowledgment = new WifiDlMuBarBaSequence;
513 }
514
515 NS_LOG_DEBUG("Adding STA " << receiver
516 << " to the list of stations receiving a BlockAckReq");
517 acknowledgment->stationsSendBlockAckReqTo.emplace(
518 receiver,
520 GetWifiRemoteStationManager()->GetBlockAckTxVector(receiver, txParams.m_txVector),
521 m_mac->GetBarTypeAsOriginator(receiver, tid),
522 GetWifiRemoteStationManager()->GetBlockAckTxVector(receiver, txParams.m_txVector),
523 m_mac->GetBaTypeAsOriginator(receiver, tid)});
524
525 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::BLOCK_ACK);
526 return std::unique_ptr<WifiDlMuBarBaSequence>(acknowledgment);
527 }
528
529 // Add the receiver as the station that will immediately reply with a Normal Ack
530 if (acknowledgment)
531 {
532 // txParams.m_acknowledgment points to an existing WifiDlMuBarBaSequence object.
533 // We have to return a copy of this object including the needed changes
534 acknowledgment = new WifiDlMuBarBaSequence(*acknowledgment);
535 }
536 else
537 {
538 // we have to create a new WifiDlMuBarBaSequence object
539 acknowledgment = new WifiDlMuBarBaSequence;
540 }
541
542 NS_LOG_DEBUG("Adding STA " << receiver
543 << " as the station that will immediately reply with a Normal Ack");
544 acknowledgment->stationsReplyingWithNormalAck.emplace(
545 receiver,
547 GetWifiRemoteStationManager()->GetAckTxVector(receiver, txParams.m_txVector)});
548
549 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::NORMAL_ACK);
550 return std::unique_ptr<WifiDlMuBarBaSequence>(acknowledgment);
551}
552
553std::unique_ptr<WifiAcknowledgment>
555 const WifiTxParameters& txParams)
556{
557 NS_LOG_FUNCTION(this << *mpdu << &txParams);
558 NS_ASSERT(txParams.m_txVector.IsDlMu());
560
561 const WifiMacHeader& hdr = mpdu->GetHeader();
562 Mac48Address receiver = hdr.GetAddr1();
563
564 NS_ASSERT(!txParams.m_acknowledgment ||
566
567 WifiDlMuTfMuBar* acknowledgment = nullptr;
568 if (txParams.m_acknowledgment)
569 {
570 acknowledgment = static_cast<WifiDlMuTfMuBar*>(txParams.m_acknowledgment.get());
571 }
572
573 if (txParams.LastAddedIsFirstMpdu(receiver))
574 {
575 // we get here if this is the first MPDU for this receiver.
577 NS_ABORT_MSG_IF(!apMac, "HE APs only can send DL MU PPDUs");
578 uint16_t staId = apMac->GetAssociationId(receiver, m_linkId);
579
581 "QoS data frames only can be aggregated when transmitting a "
582 "DL MU PPDU acknowledged via a MU-BAR sent as SU frame");
583 uint8_t tid = hdr.GetQosTid();
584
585 // Add the receiver to the list of stations that will reply with a Block Ack
586 if (acknowledgment)
587 {
588 // txParams.m_acknowledgment points to an existing WifiDlMuTfMuBar object.
589 // We have to return a copy of this object including the needed changes
590 acknowledgment = new WifiDlMuTfMuBar(*acknowledgment);
591 }
592 else
593 {
594 // we have to create a new WifiDlMuTfMuBar object
595 acknowledgment = new WifiDlMuTfMuBar;
596 }
597
598 // determine the TX vector used to send the BlockAck frame
599 WifiTxVector blockAckTxVector;
600 auto preamble = IsEht(txParams.m_txVector.GetPreambleType()) ? WIFI_PREAMBLE_EHT_TB
602 blockAckTxVector.SetPreambleType(preamble);
603 blockAckTxVector.SetChannelWidth(txParams.m_txVector.GetChannelWidth());
604 // 800ns GI is not allowed for HE TB
605 blockAckTxVector.SetGuardInterval(
606 std::max(txParams.m_txVector.GetGuardInterval(), NanoSeconds(1600)));
607 const auto& userInfo = txParams.m_txVector.GetHeMuUserInfo(staId);
608 blockAckTxVector.SetHeMuUserInfo(
609 staId,
610 {userInfo.ru, std::min(userInfo.mcs, m_maxMcsForBlockAckInTbPpdu), userInfo.nss});
611
612 NS_LOG_DEBUG("Adding STA "
613 << receiver
614 << " to the list of stations that will be solicited by the MU-BAR");
615 Ptr<QosTxop> edca = m_mac->GetQosTxop(QosUtilsMapTidToAc(tid));
616 acknowledgment->stationsReplyingWithBlockAck.emplace(
617 receiver,
618 WifiDlMuTfMuBar::BlockAckInfo{edca->GetBaManager()->GetBlockAckReqHeader(
619 mpdu->GetOriginal()->GetHeader().GetAddr1(),
620 tid),
621 blockAckTxVector,
622 m_mac->GetBaTypeAsOriginator(receiver, tid)});
623
624 acknowledgment->barTypes.push_back(m_mac->GetBarTypeAsOriginator(receiver, tid));
625 acknowledgment->muBarTxVector =
626 GetWifiRemoteStationManager()->GetRtsTxVector(receiver,
627 txParams.m_txVector.GetChannelWidth());
628 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::BLOCK_ACK);
629 return std::unique_ptr<WifiDlMuTfMuBar>(acknowledgment);
630 }
631
632 // an MPDU addressed to the same receiver has been already added
633 NS_ASSERT(acknowledgment);
635 "QoS data frames only can be aggregated when transmitting a DL MU PPDU");
636
637 // no change is needed
638 return nullptr;
639}
640
641std::unique_ptr<WifiAcknowledgment>
643 const WifiTxParameters& txParams)
644{
645 NS_LOG_FUNCTION(this << *mpdu << &txParams);
646 NS_ASSERT(txParams.m_txVector.IsDlMu());
648
649 const WifiMacHeader& hdr = mpdu->GetHeader();
650 Mac48Address receiver = hdr.GetAddr1();
651
652 NS_ASSERT(!txParams.m_acknowledgment ||
654
655 WifiDlMuAggregateTf* acknowledgment = nullptr;
656 if (txParams.m_acknowledgment)
657 {
658 acknowledgment = static_cast<WifiDlMuAggregateTf*>(txParams.m_acknowledgment.get());
659 }
660
661 if (txParams.LastAddedIsFirstMpdu(receiver))
662 {
663 // we get here if this is the first MPDU for this receiver.
665 NS_ABORT_MSG_IF(!apMac, "HE APs only can send DL MU PPDUs");
666 uint16_t staId = apMac->GetAssociationId(receiver, m_linkId);
667
669 "QoS data frames only can be aggregated when transmitting a "
670 "DL MU PPDU acknowledged via a sequence of BAR and BA frames");
671 uint8_t tid = hdr.GetQosTid();
672
673 // Add the receiver to the list of stations that will reply with a Block Ack
674 if (acknowledgment)
675 {
676 // txParams.m_acknowledgment points to an existing WifiDlMuAggregateTf object.
677 // We have to return a copy of this object including the needed changes
678 acknowledgment = new WifiDlMuAggregateTf(*acknowledgment);
679 }
680 else
681 {
682 // we have to create a new WifiDlMuAggregateTf object
683 acknowledgment = new WifiDlMuAggregateTf;
684 }
685
686 // determine the TX vector used to send the BlockAck frame
687 WifiTxVector blockAckTxVector;
688 auto preamble = IsEht(txParams.m_txVector.GetPreambleType()) ? WIFI_PREAMBLE_EHT_TB
690 blockAckTxVector.SetPreambleType(preamble);
691 blockAckTxVector.SetChannelWidth(txParams.m_txVector.GetChannelWidth());
692 // 800ns GI is not allowed for HE TB
693 blockAckTxVector.SetGuardInterval(
694 std::max(txParams.m_txVector.GetGuardInterval(), NanoSeconds(1600)));
695 const auto& userInfo = txParams.m_txVector.GetHeMuUserInfo(staId);
696 blockAckTxVector.SetHeMuUserInfo(
697 staId,
698 {userInfo.ru, std::min(userInfo.mcs, m_maxMcsForBlockAckInTbPpdu), userInfo.nss});
699
700 NS_LOG_DEBUG("Adding STA " << receiver
701 << " to the list of stations that will reply with a Block Ack");
702 Ptr<QosTxop> edca = m_mac->GetQosTxop(QosUtilsMapTidToAc(tid));
703 acknowledgment->stationsReplyingWithBlockAck.emplace(
704 receiver,
706 GetMuBarSize({m_mac->GetBarTypeAsOriginator(receiver, tid)}),
707 edca->GetBaManager()->GetBlockAckReqHeader(
708 mpdu->GetOriginal()->GetHeader().GetAddr1(),
709 tid),
710 blockAckTxVector,
711 m_mac->GetBaTypeAsOriginator(receiver, tid)});
712
713 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::NO_EXPLICIT_ACK);
714 return std::unique_ptr<WifiDlMuAggregateTf>(acknowledgment);
715 }
716
717 // an MPDU addressed to the same receiver has been already added
718 NS_ASSERT(acknowledgment);
720 !hdr.IsQosData(),
721 "QoS data and MU-BAR Trigger frames only can be aggregated when transmitting a DL MU PPDU");
722
723 // no change is needed
724 return nullptr;
725}
726
727std::unique_ptr<WifiAcknowledgment>
729 const WifiTxParameters& txParams)
730{
731 NS_LOG_FUNCTION(this << *mpdu << &txParams);
732 NS_ASSERT(mpdu->GetHeader().IsTrigger());
733
735 NS_ABORT_MSG_IF(!apMac, "HE APs only can send Trigger Frames");
736
737 auto heFem = DynamicCast<HeFrameExchangeManager>(m_mac->GetFrameExchangeManager(m_linkId));
738 NS_ABORT_MSG_IF(!heFem, "HE APs only can send Trigger Frames");
739
740 CtrlTriggerHeader trigger;
741 mpdu->GetPacket()->PeekHeader(trigger);
742
743 if (trigger.IsBasic())
744 {
745 // the only supported ack method for now is through a multi-STA BlockAck frame
746 auto acknowledgment = std::make_unique<WifiUlMuMultiStaBa>();
747
748 for (const auto& userInfo : trigger)
749 {
750 uint16_t aid12 = userInfo.GetAid12();
751
752 if (aid12 == NO_USER_STA_ID)
753 {
754 NS_LOG_INFO("Unallocated RU");
755 continue;
756 }
757 NS_ABORT_MSG_IF(aid12 == 0 || aid12 > 2007, "Allocation of RA-RUs is not supported");
758
759 const auto it = apMac->GetStaList(m_linkId).find(aid12);
760 NS_ASSERT(it != apMac->GetStaList(m_linkId).end());
761 const auto staAddress = it->second;
762
763 // find a TID for which a BA agreement exists with the given originator
764 uint8_t tid = 0;
765 while (tid < 8 && !m_mac->GetBaAgreementEstablishedAsRecipient(staAddress, tid))
766 {
767 tid++;
768 }
769 NS_ASSERT_MSG(tid < 8,
770 "No Block Ack agreement established with originator " << staAddress);
771
772 std::size_t index = acknowledgment->baType.m_bitmapLen.size();
773 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(staAddress, tid),
774 index);
775
776 // we assume the Block Acknowledgment context is used for the multi-STA BlockAck frame
777 // (since it requires the longest TX time due to the presence of a bitmap)
778 acknowledgment->baType.m_bitmapLen.push_back(
779 m_mac->GetBaTypeAsRecipient(staAddress, tid).m_bitmapLen.at(0));
780 }
781
782 uint16_t staId = trigger.begin()->GetAid12();
783 acknowledgment->tbPpduTxVector = trigger.GetHeTbTxVector(staId);
784 acknowledgment->multiStaBaTxVector = GetWifiRemoteStationManager()->GetBlockAckTxVector(
785 apMac->GetStaList(m_linkId).find(staId)->second,
786 acknowledgment->tbPpduTxVector);
787 return acknowledgment;
788 }
789 else if (trigger.IsBsrp())
790 {
791 return std::make_unique<WifiNoAck>();
792 }
793
794 return nullptr;
795}
796
797} // namespace ns3
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
#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:1380
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.
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition boolean.cc:113
Ptr< const AttributeChecker > MakeUintegerChecker()
Definition uinteger.h:85
std:: tuple< WifiContainerQueueType, WifiReceiverAddressType, Mac48Address, std::optional< uint8_t > > WifiContainerQueueId
Tuple (queue type, receiver address type, Address, TID) identifying a container queue.
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Definition uinteger.h:35
bool IsEht(WifiPreamble preamble)
Return true if a preamble corresponds to an EHT transmission.
Ptr< const AttributeChecker > MakeDoubleChecker()
Definition double.h:82
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:580
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)
uint32_t GetMuBarSize(std::list< BlockAckReqType > types)
Return the total MU-BAR size (including FCS trailer).
Definition wifi-utils.cc:80
static constexpr uint16_t SEQNO_SPACE_SIZE
Size of the space of sequence numbers.
Definition wifi-utils.h:265
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Definition boolean.h:70
Ptr< const AttributeAccessor > MakeDoubleAccessor(T1 a1)
Definition double.h:32
bool IsGcr(Ptr< WifiMac > mac, const WifiMacHeader &hdr)
Return whether a given packet is transmitted using the GCR service.
Ptr< const AttributeAccessor > MakeEnumAccessor(T1 a1)
Definition enum.h:221
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