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 "qos-utils.h"
14#include "wifi-mac-queue.h"
15#include "wifi-mpdu.h"
16#include "wifi-protection.h"
17#include "wifi-tx-parameters.h"
18
19#include "ns3/he-frame-exchange-manager.h"
20#include "ns3/log.h"
21
22namespace ns3
23{
24
25NS_LOG_COMPONENT_DEFINE("WifiDefaultAckManager");
26
27NS_OBJECT_ENSURE_REGISTERED(WifiDefaultAckManager);
28
29TypeId
31{
32 static TypeId tid =
33 TypeId("ns3::WifiDefaultAckManager")
35 .SetGroupName("Wifi")
36 .AddConstructor<WifiDefaultAckManager>()
37 .AddAttribute("UseExplicitBar",
38 "Specify whether to send Block Ack Requests (if true) or use"
39 " Implicit Block Ack Request ack policy (if false).",
40 BooleanValue(false),
43 .AddAttribute("BaThreshold",
44 "Immediate acknowledgment is requested upon transmission of a frame "
45 "whose sequence number is distant at least BaThreshold multiplied "
46 "by the transmit window size from the starting sequence number of "
47 "the transmit window. Set to zero to request a response for every "
48 "transmitted frame.",
49 DoubleValue(0.0),
52 .AddAttribute(
53 "DlMuAckSequenceType",
54 "Type of the acknowledgment sequence for DL MU PPDUs.",
58 "DL_MU_BAR_BA_SEQUENCE",
60 "DL_MU_TF_MU_BAR",
62 "DL_MU_AGGREGATE_TF"))
63 .AddAttribute("MaxBlockAckMcs",
64 "The MCS used to send a BlockAck in a TB PPDU is the minimum between "
65 "the MCS used for the PSDU sent in the preceding DL MU PPDU and the "
66 "value of this attribute.",
70 return tid;
71}
72
77
82
83uint16_t
85 const WifiTxParameters& txParams) const
86{
87 NS_LOG_FUNCTION(this << *mpdu << &txParams);
88
89 auto receiver = mpdu->GetHeader().GetAddr1();
90 auto origReceiver = mpdu->GetOriginal()->GetHeader().GetAddr1();
91
92 uint8_t tid = mpdu->GetHeader().GetQosTid();
93 Ptr<QosTxop> edca = m_mac->GetQosTxop(tid);
94 NS_ABORT_MSG_IF(!m_mac->GetBaAgreementEstablishedAsOriginator(origReceiver, tid),
95 "An established Block Ack agreement is required");
96
97 uint16_t startingSeq = edca->GetBaStartingSequence(origReceiver, tid);
98 uint16_t maxDistFromStartingSeq = 0;
99
100 const auto* psduInfo = txParams.GetPsduInfo(receiver);
101 NS_ASSERT_MSG(psduInfo && psduInfo->seqNumbers.contains(tid),
102 "There must be at least an MPDU with tid " << +tid);
103
104 const auto& seqNumbers = psduInfo->seqNumbers.at(tid);
105 NS_ASSERT_MSG(seqNumbers.contains(mpdu->GetHeader().GetSequenceNumber()),
106 "The sequence number of the given MPDU is not included in the TX parameters");
107
108 for (const auto& seqNumber : seqNumbers)
109 {
110 NS_ASSERT_MSG(!QosUtilsIsOldPacket(startingSeq, seqNumber),
111 "QoS data frame SeqN=" << seqNumber << " is too old");
112
113 uint16_t currDistToStartingSeq =
114 (seqNumber - startingSeq + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE;
115
116 if (currDistToStartingSeq > maxDistFromStartingSeq)
117 {
118 maxDistFromStartingSeq = currDistToStartingSeq;
119 }
120 }
121
122 NS_LOG_DEBUG("Returning " << maxDistFromStartingSeq);
123 return maxDistFromStartingSeq;
124}
125
126bool
128 const WifiTxParameters& txParams) const
129{
130 NS_LOG_FUNCTION(this << *mpdu << &txParams);
131
132 uint8_t tid = mpdu->GetHeader().GetQosTid();
133 auto receiver = mpdu->GetHeader().GetAddr1();
134 auto origReceiver = mpdu->GetOriginal()->GetHeader().GetAddr1();
135 Ptr<QosTxop> edca = m_mac->GetQosTxop(tid);
136 const auto& seqNumbers = txParams.GetPsduInfo(receiver)->seqNumbers.at(tid);
137
138 // An immediate response (Ack or Block Ack) is needed if any of the following holds:
139 // * the BA threshold is set to zero
140 if (m_baThreshold == 0.0)
141 {
142 return true;
143 }
144 // * the maximum distance between the sequence number of an MPDU to transmit
145 // and the starting sequence number of the transmit window is greater than
146 // or equal to the window size multiplied by the BaThreshold
147 if (GetMaxDistFromStartingSeq(mpdu, txParams) >=
148 m_baThreshold * edca->GetBaBufferSize(origReceiver, tid))
149 {
150 return true;
151 }
152 // * no other frame belonging to this BA agreement is queued (because, in such
153 // a case, a Block Ack is not going to be requested anytime soon)
154 if (auto queueId = WifiContainerQueueId(WIFI_QOSDATA_QUEUE, WIFI_UNICAST, origReceiver, tid);
155 edca->GetWifiMacQueue()->GetNPackets(queueId) -
156 edca->GetBaManager()->GetNBufferedPackets(origReceiver, tid) - seqNumbers.size() <
157 1)
158 {
159 return true;
160 }
161 // * the block ack TX window cannot advance because all the MPDUs in the TX window other than
162 // those being transmitted have been already acknowledged
163 if (m_mac->GetBaAgreementEstablishedAsOriginator(origReceiver, tid)
164 ->get()
165 .AllAckedMpdusInTxWindow(seqNumbers))
166 {
167 return true;
168 }
169
170 // * this is the initial frame of a transmission opportunity and it is not
171 // protected by RTS/CTS (see Annex G.3 of IEEE 802.11-2016)
172 if (edca->GetTxopLimit(m_linkId).IsStrictlyPositive() &&
173 edca->GetRemainingTxop(m_linkId) == edca->GetTxopLimit(m_linkId) &&
174 !(txParams.m_protection && txParams.m_protection->method == WifiProtection::RTS_CTS))
175 {
176 return true;
177 }
178
179 return false;
180}
181
182bool
184{
185 NS_ASSERT(mpdu->GetHeader().IsQosData());
186 auto tid = mpdu->GetHeader().GetQosTid();
187 NS_ASSERT(mpdu->IsQueued());
188 auto queue = m_mac->GetTxopQueue(mpdu->GetQueueAc());
189 auto origReceiver = mpdu->GetOriginal()->GetHeader().GetAddr1();
190 auto agreement = m_mac->GetBaAgreementEstablishedAsOriginator(origReceiver, tid);
191 NS_ASSERT(agreement);
192 auto mpduDist = agreement->get().GetDistance(mpdu->GetHeader().GetSequenceNumber());
193
194 Ptr<WifiMpdu> item = queue->PeekByTidAndAddress(tid, origReceiver);
195
196 while (item)
197 {
198 auto itemDist = agreement->get().GetDistance(item->GetHeader().GetSequenceNumber());
199 if (itemDist == mpduDist)
200 {
201 NS_LOG_DEBUG("No previous MPDU in-flight on the same link");
202 return false;
203 }
204 NS_ABORT_MSG_IF(itemDist > mpduDist,
205 "While searching for given MPDU ("
206 << *mpdu << "), found first another one (" << *item
207 << ") with higher sequence number");
208 if (auto linkIds = item->GetInFlightLinkIds(); linkIds.contains(m_linkId))
209 {
210 NS_LOG_DEBUG("Found MPDU inflight on the same link");
211 return true;
212 }
213 item = queue->PeekByTidAndAddress(tid, origReceiver, item);
214 }
215 NS_ABORT_MSG("Should not get here");
216 return false;
217}
218
219std::unique_ptr<WifiAcknowledgment>
221{
222 NS_LOG_FUNCTION(this << *mpdu << &txParams);
223
224 // If the TXVECTOR indicates a DL MU PPDU, call a separate method
225 if (txParams.m_txVector.IsDlMu())
226 {
227 switch (m_dlMuAckType)
228 {
230 return GetAckInfoIfBarBaSequence(mpdu, txParams);
232 return GetAckInfoIfTfMuBar(mpdu, txParams);
234 return GetAckInfoIfAggregatedMuBar(mpdu, txParams);
235 default:
236 NS_ABORT_MSG("Unknown DL acknowledgment method");
237 return nullptr;
238 }
239 }
240
241 const WifiMacHeader& hdr = mpdu->GetHeader();
242 Mac48Address receiver = hdr.GetAddr1();
243
244 // Acknowledgment for TB PPDUs
245 if (txParams.m_txVector.IsUlMu())
246 {
247 if (hdr.IsQosData() && !hdr.HasData())
248 {
249 // QoS Null frame
250 std::unique_ptr<WifiAcknowledgment> acknowledgment;
251
252 if (txParams.m_acknowledgment)
253 {
255 acknowledgment = txParams.m_acknowledgment->Copy();
256 }
257 else
258 {
259 acknowledgment = std::make_unique<WifiNoAck>();
260 }
261 acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::NO_ACK);
262 return acknowledgment;
263 }
264
265 if (txParams.m_acknowledgment)
266 {
268 return nullptr;
269 }
270
271 auto acknowledgment = std::make_unique<WifiAckAfterTbPpdu>();
272 if (hdr.IsQosData())
273 {
274 acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::NORMAL_ACK);
275 }
276 return acknowledgment;
277 }
278
279 // if this is a Trigger Frame, call a separate method
280 if (hdr.IsTrigger())
281 {
282 return TryUlMuTransmission(mpdu, txParams);
283 }
284
285 // if the current acknowledgment method (if any) is already BLOCK_ACK, it will not
286 // change by adding an MPDU
287 if (txParams.m_acknowledgment &&
289 {
290 return nullptr;
291 }
292
293 if (receiver.IsGroup())
294 {
295 NS_ABORT_MSG_IF(!txParams.LastAddedIsFirstMpdu(receiver),
296 "Unicast frames only can be aggregated");
297 auto acknowledgment = std::make_unique<WifiNoAck>();
298 if (hdr.IsQosData())
299 {
300 acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::NO_ACK);
301 }
302 return acknowledgment;
303 }
304
305 if ((!hdr.IsQosData() ||
306 !m_mac->GetBaAgreementEstablishedAsOriginator(receiver, hdr.GetQosTid())) &&
307 !hdr.IsBlockAckReq())
308 {
310 "Non-QoS data frame or Block Ack agreement not established, request Normal Ack");
311 auto acknowledgment = std::make_unique<WifiNormalAck>();
312 acknowledgment->ackTxVector =
313 GetWifiRemoteStationManager()->GetAckTxVector(receiver, txParams.m_txVector);
314 if (hdr.IsQosData())
315 {
316 acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::NORMAL_ACK);
317 }
318 return acknowledgment;
319 }
320
321 // we get here if mpdu is a QoS data frame related to an established Block Ack agreement
322 // or mpdu is a BlockAckReq frame
323 if (!hdr.IsBlockAckReq() && !IsResponseNeeded(mpdu, txParams))
324 {
325 NS_LOG_DEBUG("A response is not needed: no ack for now, use Block Ack policy");
326 if (txParams.m_acknowledgment &&
327 txParams.m_acknowledgment->method == WifiAcknowledgment::NONE)
328 {
329 // no change if the ack method is already NONE
330 return nullptr;
331 }
332
333 auto acknowledgment = std::make_unique<WifiNoAck>();
334 if (hdr.IsQosData())
335 {
336 acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::BLOCK_ACK);
337 }
338 return acknowledgment;
339 }
340
341 // we get here if a response is needed
342 uint8_t tid = GetTid(mpdu->GetPacket(), hdr);
343 if (!hdr.IsBlockAckReq() && txParams.LastAddedIsFirstMpdu(receiver) &&
345 {
346 NS_LOG_DEBUG("Sending a single MPDU, no previous frame to ack: request Normal Ack");
347 auto acknowledgment = std::make_unique<WifiNormalAck>();
348 acknowledgment->ackTxVector =
349 GetWifiRemoteStationManager()->GetAckTxVector(receiver, txParams.m_txVector);
350 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::NORMAL_ACK);
351 return acknowledgment;
352 }
353
354 // we get here if multiple MPDUs are being/have been sent
355 if (!hdr.IsBlockAckReq() && (txParams.LastAddedIsFirstMpdu(receiver) || m_useExplicitBar))
356 {
357 // in case of single MPDU, there are previous unacknowledged frames, thus
358 // we cannot use Implicit Block Ack Request policy, otherwise we get a
359 // normal ack as response
360 NS_LOG_DEBUG("Request to schedule a Block Ack Request");
361
362 auto acknowledgment = std::make_unique<WifiBarBlockAck>();
363 acknowledgment->blockAckReqTxVector =
364 GetWifiRemoteStationManager()->GetBlockAckTxVector(receiver, txParams.m_txVector);
365 acknowledgment->blockAckTxVector = acknowledgment->blockAckReqTxVector;
366 acknowledgment->barType = m_mac->GetBarTypeAsOriginator(receiver, tid);
367 acknowledgment->baType = m_mac->GetBaTypeAsOriginator(receiver, tid);
368 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::BLOCK_ACK);
369 return acknowledgment;
370 }
371
373 "A-MPDU using Implicit Block Ack Request policy or BlockAckReq, request Block Ack");
374 auto acknowledgment = std::make_unique<WifiBlockAck>();
375 acknowledgment->blockAckTxVector =
376 GetWifiRemoteStationManager()->GetBlockAckTxVector(receiver, txParams.m_txVector);
377 acknowledgment->baType = m_mac->GetBaTypeAsOriginator(receiver, tid);
378 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::NORMAL_ACK);
379 return acknowledgment;
380}
381
382std::unique_ptr<WifiAcknowledgment>
384{
385 NS_LOG_FUNCTION(this << *msdu << &txParams);
386
387 // Aggregating an MSDU does not change the acknowledgment method
388 return nullptr;
389}
390
391std::unique_ptr<WifiAcknowledgment>
393 const WifiTxParameters& txParams)
394{
395 NS_LOG_FUNCTION(this << *mpdu << &txParams);
396 NS_ASSERT(txParams.m_txVector.IsDlMu());
398
399 const WifiMacHeader& hdr = mpdu->GetHeader();
400 Mac48Address receiver = hdr.GetAddr1();
401
403 "QoS data frames only can be aggregated when transmitting a "
404 "DL MU PPDU acknowledged via a sequence of BAR and BA frames");
405 uint8_t tid = hdr.GetQosTid();
406 Ptr<QosTxop> edca = m_mac->GetQosTxop(QosUtilsMapTidToAc(tid));
407
408 NS_ASSERT(!txParams.m_acknowledgment ||
410
411 WifiDlMuBarBaSequence* acknowledgment = nullptr;
412 if (txParams.m_acknowledgment)
413 {
414 acknowledgment = static_cast<WifiDlMuBarBaSequence*>(txParams.m_acknowledgment.get());
415 }
416
417 if (!txParams.LastAddedIsFirstMpdu(receiver))
418 {
419 // an MPDU addressed to the same receiver has been already added
420 NS_ASSERT(acknowledgment);
421
422 if (acknowledgment->stationsSendBlockAckReqTo.contains(receiver) ||
423 acknowledgment->stationsReplyingWithBlockAck.contains(receiver))
424 {
425 // the receiver either is already listed among the stations that will
426 // receive a BlockAckReq frame or is the station that will immediately
427 // respond with a BlockAck frame, hence no change is needed
428 return nullptr;
429 }
430
431 // the receiver was scheduled for responding immediately with a Normal Ack.
432 // Given that we are adding an MPDU, the receiver must be scheduled for
433 // responding immediately with a Block Ack
434 NS_ASSERT(acknowledgment->stationsReplyingWithNormalAck.size() == 1 &&
435 acknowledgment->stationsReplyingWithNormalAck.begin()->first == receiver);
436
437 // acknowledgment points to the m_acknowledgment member of txParams, which is
438 // passed as const reference because it must not be modified. Therefore, we
439 // make a copy of the object pointed to by acknowledgment and make changes to
440 // the copy
441 acknowledgment = new WifiDlMuBarBaSequence(*acknowledgment);
442 acknowledgment->stationsReplyingWithNormalAck.clear();
443
444 acknowledgment->stationsReplyingWithBlockAck.emplace(
445 receiver,
447 GetWifiRemoteStationManager()->GetBlockAckTxVector(receiver, txParams.m_txVector),
448 m_mac->GetBaTypeAsOriginator(receiver, tid)});
449 return std::unique_ptr<WifiDlMuBarBaSequence>(acknowledgment);
450 }
451
452 // we get here if this is the first MPDU for this receiver
453 auto htFem = DynamicCast<HtFrameExchangeManager>(m_mac->GetFrameExchangeManager(m_linkId));
454 NS_ASSERT(htFem);
455 if (auto bar = htFem->GetBar(QosUtilsMapTidToAc(tid), tid, receiver);
456 bar || (acknowledgment && (!acknowledgment->stationsReplyingWithNormalAck.empty() ||
457 !acknowledgment->stationsReplyingWithBlockAck.empty())))
458 {
459 // there is a pending BlockAckReq for this receiver or another receiver
460 // was selected for immediate response.
461 // Add this receiver to the list of stations receiving a BlockAckReq.
462 if (acknowledgment)
463 {
464 // txParams.m_acknowledgment points to an existing WifiDlMuBarBaSequence object.
465 // We have to return a copy of this object including the needed changes
466 acknowledgment = new WifiDlMuBarBaSequence(*acknowledgment);
467 }
468 else
469 {
470 // we have to create a new WifiDlMuBarBaSequence object
471 acknowledgment = new WifiDlMuBarBaSequence;
472 }
473
474 NS_LOG_DEBUG("Adding STA " << receiver
475 << " to the list of stations receiving a BlockAckReq");
476 acknowledgment->stationsSendBlockAckReqTo.emplace(
477 receiver,
479 GetWifiRemoteStationManager()->GetBlockAckTxVector(receiver, txParams.m_txVector),
480 m_mac->GetBarTypeAsOriginator(receiver, tid),
481 GetWifiRemoteStationManager()->GetBlockAckTxVector(receiver, txParams.m_txVector),
482 m_mac->GetBaTypeAsOriginator(receiver, tid)});
483
484 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::BLOCK_ACK);
485 return std::unique_ptr<WifiDlMuBarBaSequence>(acknowledgment);
486 }
487
488 // Add the receiver as the station that will immediately reply with a Normal Ack
489 if (acknowledgment)
490 {
491 // txParams.m_acknowledgment points to an existing WifiDlMuBarBaSequence object.
492 // We have to return a copy of this object including the needed changes
493 acknowledgment = new WifiDlMuBarBaSequence(*acknowledgment);
494 }
495 else
496 {
497 // we have to create a new WifiDlMuBarBaSequence object
498 acknowledgment = new WifiDlMuBarBaSequence;
499 }
500
501 NS_LOG_DEBUG("Adding STA " << receiver
502 << " as the station that will immediately reply with a Normal Ack");
503 acknowledgment->stationsReplyingWithNormalAck.emplace(
504 receiver,
506 GetWifiRemoteStationManager()->GetAckTxVector(receiver, txParams.m_txVector)});
507
508 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::NORMAL_ACK);
509 return std::unique_ptr<WifiDlMuBarBaSequence>(acknowledgment);
510}
511
512std::unique_ptr<WifiAcknowledgment>
514 const WifiTxParameters& txParams)
515{
516 NS_LOG_FUNCTION(this << *mpdu << &txParams);
517 NS_ASSERT(txParams.m_txVector.IsDlMu());
519
520 const WifiMacHeader& hdr = mpdu->GetHeader();
521 Mac48Address receiver = hdr.GetAddr1();
522
523 NS_ASSERT(!txParams.m_acknowledgment ||
525
526 WifiDlMuTfMuBar* acknowledgment = nullptr;
527 if (txParams.m_acknowledgment)
528 {
529 acknowledgment = static_cast<WifiDlMuTfMuBar*>(txParams.m_acknowledgment.get());
530 }
531
532 if (txParams.LastAddedIsFirstMpdu(receiver))
533 {
534 // we get here if this is the first MPDU for this receiver.
536 NS_ABORT_MSG_IF(!apMac, "HE APs only can send DL MU PPDUs");
537 uint16_t staId = apMac->GetAssociationId(receiver, m_linkId);
538
540 "QoS data frames only can be aggregated when transmitting a "
541 "DL MU PPDU acknowledged via a MU-BAR sent as SU frame");
542 uint8_t tid = hdr.GetQosTid();
543
544 // Add the receiver to the list of stations that will reply with a Block Ack
545 if (acknowledgment)
546 {
547 // txParams.m_acknowledgment points to an existing WifiDlMuTfMuBar object.
548 // We have to return a copy of this object including the needed changes
549 acknowledgment = new WifiDlMuTfMuBar(*acknowledgment);
550 }
551 else
552 {
553 // we have to create a new WifiDlMuTfMuBar object
554 acknowledgment = new WifiDlMuTfMuBar;
555 }
556
557 // determine the TX vector used to send the BlockAck frame
558 WifiTxVector blockAckTxVector;
559 auto preamble = IsEht(txParams.m_txVector.GetPreambleType()) ? WIFI_PREAMBLE_EHT_TB
561 blockAckTxVector.SetPreambleType(preamble);
562 blockAckTxVector.SetChannelWidth(txParams.m_txVector.GetChannelWidth());
563 // 800ns GI is not allowed for HE TB
564 blockAckTxVector.SetGuardInterval(
565 std::max(txParams.m_txVector.GetGuardInterval(), NanoSeconds(1600)));
566 const auto& userInfo = txParams.m_txVector.GetHeMuUserInfo(staId);
567 blockAckTxVector.SetHeMuUserInfo(
568 staId,
569 {userInfo.ru, std::min(userInfo.mcs, m_maxMcsForBlockAckInTbPpdu), userInfo.nss});
570
571 NS_LOG_DEBUG("Adding STA "
572 << receiver
573 << " to the list of stations that will be solicited by the MU-BAR");
574 Ptr<QosTxop> edca = m_mac->GetQosTxop(QosUtilsMapTidToAc(tid));
575 acknowledgment->stationsReplyingWithBlockAck.emplace(
576 receiver,
577 WifiDlMuTfMuBar::BlockAckInfo{edca->GetBaManager()->GetBlockAckReqHeader(
578 mpdu->GetOriginal()->GetHeader().GetAddr1(),
579 tid),
580 blockAckTxVector,
581 m_mac->GetBaTypeAsOriginator(receiver, tid)});
582
583 acknowledgment->barTypes.push_back(m_mac->GetBarTypeAsOriginator(receiver, tid));
584 acknowledgment->muBarTxVector =
585 GetWifiRemoteStationManager()->GetRtsTxVector(receiver,
586 txParams.m_txVector.GetChannelWidth());
587 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::BLOCK_ACK);
588 return std::unique_ptr<WifiDlMuTfMuBar>(acknowledgment);
589 }
590
591 // an MPDU addressed to the same receiver has been already added
592 NS_ASSERT(acknowledgment);
594 "QoS data frames only can be aggregated when transmitting a DL MU PPDU");
595
596 // no change is needed
597 return nullptr;
598}
599
600std::unique_ptr<WifiAcknowledgment>
602 const WifiTxParameters& txParams)
603{
604 NS_LOG_FUNCTION(this << *mpdu << &txParams);
605 NS_ASSERT(txParams.m_txVector.IsDlMu());
607
608 const WifiMacHeader& hdr = mpdu->GetHeader();
609 Mac48Address receiver = hdr.GetAddr1();
610
611 NS_ASSERT(!txParams.m_acknowledgment ||
613
614 WifiDlMuAggregateTf* acknowledgment = nullptr;
615 if (txParams.m_acknowledgment)
616 {
617 acknowledgment = static_cast<WifiDlMuAggregateTf*>(txParams.m_acknowledgment.get());
618 }
619
620 if (txParams.LastAddedIsFirstMpdu(receiver))
621 {
622 // we get here if this is the first MPDU for this receiver.
624 NS_ABORT_MSG_IF(!apMac, "HE APs only can send DL MU PPDUs");
625 uint16_t staId = apMac->GetAssociationId(receiver, m_linkId);
626
628 "QoS data frames only can be aggregated when transmitting a "
629 "DL MU PPDU acknowledged via a sequence of BAR and BA frames");
630 uint8_t tid = hdr.GetQosTid();
631
632 // Add the receiver to the list of stations that will reply with a Block Ack
633 if (acknowledgment)
634 {
635 // txParams.m_acknowledgment points to an existing WifiDlMuAggregateTf object.
636 // We have to return a copy of this object including the needed changes
637 acknowledgment = new WifiDlMuAggregateTf(*acknowledgment);
638 }
639 else
640 {
641 // we have to create a new WifiDlMuAggregateTf object
642 acknowledgment = new WifiDlMuAggregateTf;
643 }
644
645 // determine the TX vector used to send the BlockAck frame
646 WifiTxVector blockAckTxVector;
647 auto preamble = IsEht(txParams.m_txVector.GetPreambleType()) ? WIFI_PREAMBLE_EHT_TB
649 blockAckTxVector.SetPreambleType(preamble);
650 blockAckTxVector.SetChannelWidth(txParams.m_txVector.GetChannelWidth());
651 // 800ns GI is not allowed for HE TB
652 blockAckTxVector.SetGuardInterval(
653 std::max(txParams.m_txVector.GetGuardInterval(), NanoSeconds(1600)));
654 const auto& userInfo = txParams.m_txVector.GetHeMuUserInfo(staId);
655 blockAckTxVector.SetHeMuUserInfo(
656 staId,
657 {userInfo.ru, std::min(userInfo.mcs, m_maxMcsForBlockAckInTbPpdu), userInfo.nss});
658
659 NS_LOG_DEBUG("Adding STA " << receiver
660 << " to the list of stations that will reply with a Block Ack");
661 Ptr<QosTxop> edca = m_mac->GetQosTxop(QosUtilsMapTidToAc(tid));
662 acknowledgment->stationsReplyingWithBlockAck.emplace(
663 receiver,
665 GetMuBarSize({m_mac->GetBarTypeAsOriginator(receiver, tid)}),
666 edca->GetBaManager()->GetBlockAckReqHeader(
667 mpdu->GetOriginal()->GetHeader().GetAddr1(),
668 tid),
669 blockAckTxVector,
670 m_mac->GetBaTypeAsOriginator(receiver, tid)});
671
672 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::NO_EXPLICIT_ACK);
673 return std::unique_ptr<WifiDlMuAggregateTf>(acknowledgment);
674 }
675
676 // an MPDU addressed to the same receiver has been already added
677 NS_ASSERT(acknowledgment);
679 !hdr.IsQosData(),
680 "QoS data and MU-BAR Trigger frames only can be aggregated when transmitting a DL MU PPDU");
681
682 // no change is needed
683 return nullptr;
684}
685
686std::unique_ptr<WifiAcknowledgment>
688 const WifiTxParameters& txParams)
689{
690 NS_LOG_FUNCTION(this << *mpdu << &txParams);
691 NS_ASSERT(mpdu->GetHeader().IsTrigger());
692
694 NS_ABORT_MSG_IF(!apMac, "HE APs only can send Trigger Frames");
695
696 auto heFem = DynamicCast<HeFrameExchangeManager>(m_mac->GetFrameExchangeManager(m_linkId));
697 NS_ABORT_MSG_IF(!heFem, "HE APs only can send Trigger Frames");
698
699 CtrlTriggerHeader trigger;
700 mpdu->GetPacket()->PeekHeader(trigger);
701
702 if (trigger.IsBasic())
703 {
704 // the only supported ack method for now is through a multi-STA BlockAck frame
705 auto acknowledgment = std::make_unique<WifiUlMuMultiStaBa>();
706
707 for (const auto& userInfo : trigger)
708 {
709 uint16_t aid12 = userInfo.GetAid12();
710
711 if (aid12 == NO_USER_STA_ID)
712 {
713 NS_LOG_INFO("Unallocated RU");
714 continue;
715 }
716 NS_ABORT_MSG_IF(aid12 == 0 || aid12 > 2007, "Allocation of RA-RUs is not supported");
717
718 const auto it = apMac->GetStaList(m_linkId).find(aid12);
719 NS_ASSERT(it != apMac->GetStaList(m_linkId).end());
720 const auto staAddress = it->second;
721
722 // find a TID for which a BA agreement exists with the given originator
723 uint8_t tid = 0;
724 while (tid < 8 && !m_mac->GetBaAgreementEstablishedAsRecipient(staAddress, tid))
725 {
726 tid++;
727 }
728 NS_ASSERT_MSG(tid < 8,
729 "No Block Ack agreement established with originator " << staAddress);
730
731 std::size_t index = acknowledgment->baType.m_bitmapLen.size();
732 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(staAddress, tid),
733 index);
734
735 // we assume the Block Acknowledgment context is used for the multi-STA BlockAck frame
736 // (since it requires the longest TX time due to the presence of a bitmap)
737 acknowledgment->baType.m_bitmapLen.push_back(
738 m_mac->GetBaTypeAsRecipient(staAddress, tid).m_bitmapLen.at(0));
739 }
740
741 uint16_t staId = trigger.begin()->GetAid12();
742 acknowledgment->tbPpduTxVector = trigger.GetHeTbTxVector(staId);
743 acknowledgment->multiStaBaTxVector = GetWifiRemoteStationManager()->GetBlockAckTxVector(
744 apMac->GetStaList(m_linkId).find(staId)->second,
745 acknowledgment->tbPpduTxVector);
746 return acknowledgment;
747 }
748 else if (trigger.IsBsrp())
749 {
750 return std::make_unique<WifiNoAck>();
751 }
752
753 return nullptr;
754}
755
756} // namespace ns3
AttributeValue implementation for Boolean.
Definition boolean.h:26
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:48
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: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.
std:: tuple< WifiContainerQueueType, WifiReceiverAddressType, Mac48Address, std::optional< uint8_t > > WifiContainerQueueId
Tuple (queue type, receiver address type, Address, TID) identifying a container queue.
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: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:78
static constexpr uint16_t SEQNO_SPACE_SIZE
Size of the space of sequence numbers.
Definition wifi-utils.h:185
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