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 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 * Author: Stefano Avallone <stavallo@unina.it>
18 */
19
21
22#include "ap-wifi-mac.h"
23#include "ctrl-headers.h"
24#include "qos-utils.h"
25#include "wifi-mac-queue.h"
26#include "wifi-mpdu.h"
27#include "wifi-protection.h"
28#include "wifi-tx-parameters.h"
29
30#include "ns3/he-frame-exchange-manager.h"
31#include "ns3/log.h"
32
33namespace ns3
34{
35
36NS_LOG_COMPONENT_DEFINE("WifiDefaultAckManager");
37
38NS_OBJECT_ENSURE_REGISTERED(WifiDefaultAckManager);
39
40TypeId
42{
43 static TypeId tid =
44 TypeId("ns3::WifiDefaultAckManager")
46 .SetGroupName("Wifi")
47 .AddConstructor<WifiDefaultAckManager>()
48 .AddAttribute("UseExplicitBar",
49 "Specify whether to send Block Ack Requests (if true) or use"
50 " Implicit Block Ack Request ack policy (if false).",
51 BooleanValue(false),
54 .AddAttribute("BaThreshold",
55 "Immediate acknowledgment is requested upon transmission of a frame "
56 "whose sequence number is distant at least BaThreshold multiplied "
57 "by the transmit window size from the starting sequence number of "
58 "the transmit window. Set to zero to request a response for every "
59 "transmitted frame.",
60 DoubleValue(0.0),
62 MakeDoubleChecker<double>(0.0, 1.0))
63 .AddAttribute("DlMuAckSequenceType",
64 "Type of the acknowledgment sequence for DL MU PPDUs.",
68 "DL_MU_BAR_BA_SEQUENCE",
70 "DL_MU_TF_MU_BAR",
72 "DL_MU_AGGREGATE_TF"))
73 .AddAttribute("MaxBlockAckMcs",
74 "The MCS used to send a BlockAck in a TB PPDU is the minimum between "
75 "the MCS used for the PSDU sent in the preceding DL MU PPDU and the "
76 "value of this attribute.",
79 MakeUintegerChecker<uint8_t>(0, 11));
80 return tid;
81}
82
84{
85 NS_LOG_FUNCTION(this);
86}
87
89{
91}
92
93uint16_t
95 const WifiTxParameters& txParams) const
96{
97 NS_LOG_FUNCTION(this << *mpdu << &txParams);
98
99 auto receiver = mpdu->GetHeader().GetAddr1();
100 auto origReceiver = mpdu->GetOriginal()->GetHeader().GetAddr1();
101
102 uint8_t tid = mpdu->GetHeader().GetQosTid();
103 Ptr<QosTxop> edca = m_mac->GetQosTxop(tid);
105 "An established Block Ack agreement is required");
106
107 uint16_t startingSeq = edca->GetBaStartingSequence(origReceiver, tid);
108 uint16_t maxDistFromStartingSeq =
109 (mpdu->GetHeader().GetSequenceNumber() - startingSeq + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE;
110 NS_ABORT_MSG_IF(maxDistFromStartingSeq >= SEQNO_SPACE_HALF_SIZE,
111 "The given QoS data frame is too old");
112
113 const WifiTxParameters::PsduInfo* psduInfo = txParams.GetPsduInfo(receiver);
114
115 if (!psduInfo || psduInfo->seqNumbers.find(tid) == psduInfo->seqNumbers.end())
116 {
117 // there are no aggregated MPDUs (so far)
118 return maxDistFromStartingSeq;
119 }
120
121 for (const auto& seqNumber : psduInfo->seqNumbers.at(tid))
122 {
123 if (!QosUtilsIsOldPacket(startingSeq, seqNumber))
124 {
125 uint16_t currDistToStartingSeq =
126 (seqNumber - startingSeq + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE;
127
128 if (currDistToStartingSeq > maxDistFromStartingSeq)
129 {
130 maxDistFromStartingSeq = currDistToStartingSeq;
131 }
132 }
133 }
134
135 NS_LOG_DEBUG("Returning " << maxDistFromStartingSeq);
136 return maxDistFromStartingSeq;
137}
138
139bool
141 const WifiTxParameters& txParams) const
142{
143 NS_LOG_FUNCTION(this << *mpdu << &txParams);
144
145 uint8_t tid = mpdu->GetHeader().GetQosTid();
146 Mac48Address receiver = mpdu->GetOriginal()->GetHeader().GetAddr1();
147 Ptr<QosTxop> edca = m_mac->GetQosTxop(tid);
148
149 // An immediate response (Ack or Block Ack) is needed if any of the following holds:
150 // * the maximum distance between the sequence number of an MPDU to transmit
151 // and the starting sequence number of the transmit window is greater than
152 // or equal to the window size multiplied by the BaThreshold
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 // * this is the initial frame of a transmission opportunity and it is not
156 // protected by RTS/CTS (see Annex G.3 of IEEE 802.11-2016)
157 return !(
158 m_baThreshold > 0 &&
159 GetMaxDistFromStartingSeq(mpdu, txParams) <
160 m_baThreshold * edca->GetBaBufferSize(receiver, tid) &&
161 (edca->GetWifiMacQueue()->GetNPackets({WIFI_QOSDATA_QUEUE, WIFI_UNICAST, receiver, tid}) -
162 edca->GetBaManager()->GetNBufferedPackets(receiver, tid) >
163 1) &&
164 !(edca->GetTxopLimit(m_linkId).IsStrictlyPositive() &&
165 edca->GetRemainingTxop(m_linkId) == edca->GetTxopLimit(m_linkId) &&
166 !(txParams.m_protection && txParams.m_protection->method == WifiProtection::RTS_CTS)));
167}
168
169bool
171{
172 NS_ASSERT(mpdu->GetHeader().IsQosData());
173 auto tid = mpdu->GetHeader().GetQosTid();
174 NS_ASSERT(mpdu->IsQueued());
175 auto queue = m_mac->GetTxopQueue(mpdu->GetQueueAc());
176 auto origReceiver = mpdu->GetOriginal()->GetHeader().GetAddr1();
177 auto agreement = m_mac->GetBaAgreementEstablishedAsOriginator(origReceiver, tid);
178 NS_ASSERT(agreement);
179 auto mpduDist = agreement->get().GetDistance(mpdu->GetHeader().GetSequenceNumber());
180
181 Ptr<WifiMpdu> item = queue->PeekByTidAndAddress(tid, origReceiver);
182
183 while (item)
184 {
185 auto itemDist = agreement->get().GetDistance(item->GetHeader().GetSequenceNumber());
186 if (itemDist == mpduDist)
187 {
188 NS_LOG_DEBUG("No previous MPDU in-flight on the same link");
189 return false;
190 }
191 NS_ABORT_MSG_IF(itemDist > mpduDist,
192 "While searching for given MPDU ("
193 << *mpdu << "), found first another one (" << *item
194 << ") with higher sequence number");
195 if (auto linkIds = item->GetInFlightLinkIds(); linkIds.count(m_linkId) > 0)
196 {
197 NS_LOG_DEBUG("Found MPDU inflight on the same link");
198 return true;
199 }
200 item = queue->PeekByTidAndAddress(tid, origReceiver, item);
201 }
202 NS_ABORT_MSG("Should not get here");
203 return false;
204}
205
206std::unique_ptr<WifiAcknowledgment>
208{
209 NS_LOG_FUNCTION(this << *mpdu << &txParams);
210
211 // If the TXVECTOR indicates a DL MU PPDU, call a separate method
212 if (txParams.m_txVector.IsDlMu())
213 {
214 switch (m_dlMuAckType)
215 {
217 return GetAckInfoIfBarBaSequence(mpdu, txParams);
219 return GetAckInfoIfTfMuBar(mpdu, txParams);
221 return GetAckInfoIfAggregatedMuBar(mpdu, txParams);
222 default:
223 NS_ABORT_MSG("Unknown DL acknowledgment method");
224 return nullptr;
225 }
226 }
227
228 const WifiMacHeader& hdr = mpdu->GetHeader();
229 Mac48Address receiver = hdr.GetAddr1();
230
231 // Acknowledgment for TB PPDUs
232 if (txParams.m_txVector.IsUlMu())
233 {
234 if (hdr.IsQosData() && !hdr.HasData())
235 {
236 // QoS Null frame
237 std::unique_ptr<WifiAcknowledgment> acknowledgment;
238
239 if (txParams.m_acknowledgment)
240 {
242 acknowledgment = txParams.m_acknowledgment->Copy();
243 }
244 else
245 {
246 acknowledgment = std::make_unique<WifiNoAck>();
247 }
248 acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::NO_ACK);
249 return acknowledgment;
250 }
251
252 if (txParams.m_acknowledgment)
253 {
255 return nullptr;
256 }
257
258 auto acknowledgment = std::make_unique<WifiAckAfterTbPpdu>();
259 if (hdr.IsQosData())
260 {
261 acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::NORMAL_ACK);
262 }
263 return acknowledgment;
264 }
265
266 // if this is a Trigger Frame, call a separate method
267 if (hdr.IsTrigger())
268 {
269 return TryUlMuTransmission(mpdu, txParams);
270 }
271
272 // if the current acknowledgment method (if any) is already BLOCK_ACK, it will not
273 // change by adding an MPDU
274 if (txParams.m_acknowledgment &&
276 {
277 return nullptr;
278 }
279
280 if (receiver.IsGroup())
281 {
282 NS_ABORT_MSG_IF(txParams.GetSize(receiver) > 0, "Unicast frames only can be aggregated");
283 auto acknowledgment = std::make_unique<WifiNoAck>();
284 if (hdr.IsQosData())
285 {
286 acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::NO_ACK);
287 }
288 return acknowledgment;
289 }
290
291 if ((!hdr.IsQosData() ||
293 !hdr.IsBlockAckReq())
294 {
296 "Non-QoS data frame or Block Ack agreement not established, request Normal Ack");
297 auto acknowledgment = std::make_unique<WifiNormalAck>();
298 acknowledgment->ackTxVector =
300 if (hdr.IsQosData())
301 {
302 acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::NORMAL_ACK);
303 }
304 return acknowledgment;
305 }
306
307 // we get here if mpdu is a QoS data frame related to an established Block Ack agreement
308 // or mpdu is a BlockAckReq frame
309 if (!hdr.IsBlockAckReq() && !IsResponseNeeded(mpdu, txParams))
310 {
311 NS_LOG_DEBUG("A response is not needed: no ack for now, use Block Ack policy");
312 if (txParams.m_acknowledgment &&
313 txParams.m_acknowledgment->method == WifiAcknowledgment::NONE)
314 {
315 // no change if the ack method is already NONE
316 return nullptr;
317 }
318
319 auto acknowledgment = std::make_unique<WifiNoAck>();
320 if (hdr.IsQosData())
321 {
322 acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::BLOCK_ACK);
323 }
324 return acknowledgment;
325 }
326
327 // we get here if a response is needed
328 uint8_t tid = GetTid(mpdu->GetPacket(), hdr);
329 if (!hdr.IsBlockAckReq() && txParams.GetSize(receiver) == 0 && !ExistInflightOnSameLink(mpdu))
330 {
331 NS_LOG_DEBUG("Sending a single MPDU, no previous frame to ack: request Normal Ack");
332 auto acknowledgment = std::make_unique<WifiNormalAck>();
333 acknowledgment->ackTxVector =
335 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::NORMAL_ACK);
336 return acknowledgment;
337 }
338
339 // we get here if multiple MPDUs are being/have been sent
340 if (!hdr.IsBlockAckReq() && (txParams.GetSize(receiver) == 0 || m_useExplicitBar))
341 {
342 // in case of single MPDU, there are previous unacknowledged frames, thus
343 // we cannot use Implicit Block Ack Request policy, otherwise we get a
344 // normal ack as response
345 NS_LOG_DEBUG("Request to schedule a Block Ack Request");
346
347 auto acknowledgment = std::make_unique<WifiBarBlockAck>();
348 acknowledgment->blockAckReqTxVector =
350 acknowledgment->blockAckTxVector = acknowledgment->blockAckReqTxVector;
351 acknowledgment->barType = m_mac->GetBarTypeAsOriginator(receiver, tid);
352 acknowledgment->baType = m_mac->GetBaTypeAsOriginator(receiver, tid);
353 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::BLOCK_ACK);
354 return acknowledgment;
355 }
356
358 "A-MPDU using Implicit Block Ack Request policy or BlockAckReq, request Block Ack");
359 auto acknowledgment = std::make_unique<WifiBlockAck>();
360 acknowledgment->blockAckTxVector =
362 acknowledgment->baType = m_mac->GetBaTypeAsOriginator(receiver, tid);
363 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::NORMAL_ACK);
364 return acknowledgment;
365}
366
367std::unique_ptr<WifiAcknowledgment>
369{
370 NS_LOG_FUNCTION(this << *msdu << &txParams);
371
372 // Aggregating an MSDU does not change the acknowledgment method
373 return nullptr;
374}
375
376std::unique_ptr<WifiAcknowledgment>
378 const WifiTxParameters& txParams)
379{
380 NS_LOG_FUNCTION(this << *mpdu << &txParams);
381 NS_ASSERT(txParams.m_txVector.IsDlMu());
383
384 const WifiMacHeader& hdr = mpdu->GetHeader();
385 Mac48Address receiver = hdr.GetAddr1();
386
387 const WifiTxParameters::PsduInfo* psduInfo = txParams.GetPsduInfo(receiver);
388
390 "QoS data frames only can be aggregated when transmitting a "
391 "DL MU PPDU acknowledged via a sequence of BAR and BA frames");
392 uint8_t tid = hdr.GetQosTid();
394
395 NS_ASSERT(!txParams.m_acknowledgment ||
397
398 WifiDlMuBarBaSequence* acknowledgment = nullptr;
399 if (txParams.m_acknowledgment)
400 {
401 acknowledgment = static_cast<WifiDlMuBarBaSequence*>(txParams.m_acknowledgment.get());
402 }
403
404 if (psduInfo)
405 {
406 // an MPDU addressed to the same receiver has been already added
407 NS_ASSERT(acknowledgment);
408
409 if ((acknowledgment->stationsSendBlockAckReqTo.find(receiver) !=
410 acknowledgment->stationsSendBlockAckReqTo.end()) ||
411 (acknowledgment->stationsReplyingWithBlockAck.find(receiver) !=
412 acknowledgment->stationsReplyingWithBlockAck.end()))
413 {
414 // the receiver either is already listed among the stations that will
415 // receive a BlockAckReq frame or is the station that will immediately
416 // respond with a BlockAck frame, hence no change is needed
417 return nullptr;
418 }
419
420 // the receiver was scheduled for responding immediately with a Normal Ack.
421 // Given that we are adding an MPDU, the receiver must be scheduled for
422 // responding immediately with a Block Ack
423 NS_ASSERT(acknowledgment->stationsReplyingWithNormalAck.size() == 1 &&
424 acknowledgment->stationsReplyingWithNormalAck.begin()->first == receiver);
425
426 // acknowledgment points to the m_acknowledgment member of txParams, which is
427 // passed as const reference because it must not be modified. Therefore, we
428 // make a copy of the object pointed to by acknowledgment and make changes to
429 // the copy
430 acknowledgment = new WifiDlMuBarBaSequence(*acknowledgment);
431 acknowledgment->stationsReplyingWithNormalAck.clear();
432
433 acknowledgment->stationsReplyingWithBlockAck.emplace(
434 receiver,
437 m_mac->GetBaTypeAsOriginator(receiver, tid)});
438 return std::unique_ptr<WifiDlMuBarBaSequence>(acknowledgment);
439 }
440
441 // we get here if this is the first MPDU for this receiver
442 auto htFem = DynamicCast<HtFrameExchangeManager>(m_mac->GetFrameExchangeManager(m_linkId));
443 NS_ASSERT(htFem);
444 if (auto bar = htFem->GetBar(QosUtilsMapTidToAc(tid), tid, receiver);
445 bar || (acknowledgment && (!acknowledgment->stationsReplyingWithNormalAck.empty() ||
446 !acknowledgment->stationsReplyingWithBlockAck.empty())))
447 {
448 // there is a pending BlockAckReq for this receiver or another receiver
449 // was selected for immediate response.
450 // Add this receiver to the list of stations receiving a BlockAckReq.
451 if (acknowledgment)
452 {
453 // txParams.m_acknowledgment points to an existing WifiDlMuBarBaSequence object.
454 // We have to return a copy of this object including the needed changes
455 acknowledgment = new WifiDlMuBarBaSequence(*acknowledgment);
456 }
457 else
458 {
459 // we have to create a new WifiDlMuBarBaSequence object
460 acknowledgment = new WifiDlMuBarBaSequence;
461 }
462
463 NS_LOG_DEBUG("Adding STA " << receiver
464 << " to the list of stations receiving a BlockAckReq");
465 acknowledgment->stationsSendBlockAckReqTo.emplace(
466 receiver,
469 m_mac->GetBarTypeAsOriginator(receiver, tid),
471 m_mac->GetBaTypeAsOriginator(receiver, tid)});
472
473 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::BLOCK_ACK);
474 return std::unique_ptr<WifiDlMuBarBaSequence>(acknowledgment);
475 }
476
477 // Add the receiver as the station that will immediately reply with a Normal Ack
478 if (acknowledgment)
479 {
480 // txParams.m_acknowledgment points to an existing WifiDlMuBarBaSequence object.
481 // We have to return a copy of this object including the needed changes
482 acknowledgment = new WifiDlMuBarBaSequence(*acknowledgment);
483 }
484 else
485 {
486 // we have to create a new WifiDlMuBarBaSequence object
487 acknowledgment = new WifiDlMuBarBaSequence;
488 }
489
490 NS_LOG_DEBUG("Adding STA " << receiver
491 << " as the station that will immediately reply with a Normal Ack");
492 acknowledgment->stationsReplyingWithNormalAck.emplace(
493 receiver,
496
497 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::NORMAL_ACK);
498 return std::unique_ptr<WifiDlMuBarBaSequence>(acknowledgment);
499}
500
501std::unique_ptr<WifiAcknowledgment>
503 const WifiTxParameters& txParams)
504{
505 NS_LOG_FUNCTION(this << *mpdu << &txParams);
506 NS_ASSERT(txParams.m_txVector.IsDlMu());
508
509 const WifiMacHeader& hdr = mpdu->GetHeader();
510 Mac48Address receiver = hdr.GetAddr1();
511
512 const WifiTxParameters::PsduInfo* psduInfo = txParams.GetPsduInfo(receiver);
513
514 NS_ASSERT(!txParams.m_acknowledgment ||
516
517 WifiDlMuTfMuBar* acknowledgment = nullptr;
518 if (txParams.m_acknowledgment)
519 {
520 acknowledgment = static_cast<WifiDlMuTfMuBar*>(txParams.m_acknowledgment.get());
521 }
522
523 if (!psduInfo)
524 {
525 // we get here if this is the first MPDU for this receiver.
526 Ptr<ApWifiMac> apMac = DynamicCast<ApWifiMac>(m_mac);
527 NS_ABORT_MSG_IF(!apMac, "HE APs only can send DL MU PPDUs");
528 uint16_t staId = apMac->GetAssociationId(receiver, m_linkId);
529
531 "QoS data frames only can be aggregated when transmitting a "
532 "DL MU PPDU acknowledged via a MU-BAR sent as SU frame");
533 uint8_t tid = hdr.GetQosTid();
534
535 // Add the receiver to the list of stations that will reply with a Block Ack
536 if (acknowledgment)
537 {
538 // txParams.m_acknowledgment points to an existing WifiDlMuTfMuBar object.
539 // We have to return a copy of this object including the needed changes
540 acknowledgment = new WifiDlMuTfMuBar(*acknowledgment);
541 }
542 else
543 {
544 // we have to create a new WifiDlMuTfMuBar object
545 acknowledgment = new WifiDlMuTfMuBar;
546 }
547
548 // determine the TX vector used to send the BlockAck frame
549 WifiTxVector blockAckTxVector;
550 auto preamble = IsEht(txParams.m_txVector.GetPreambleType()) ? WIFI_PREAMBLE_EHT_TB
552 blockAckTxVector.SetPreambleType(preamble);
553 blockAckTxVector.SetChannelWidth(txParams.m_txVector.GetChannelWidth());
554 // 800ns GI is not allowed for HE TB
555 blockAckTxVector.SetGuardInterval(
556 std::max<uint16_t>(txParams.m_txVector.GetGuardInterval(), 1600));
557 const auto& userInfo = txParams.m_txVector.GetHeMuUserInfo(staId);
558 blockAckTxVector.SetHeMuUserInfo(
559 staId,
560 {userInfo.ru, std::min(userInfo.mcs, m_maxMcsForBlockAckInTbPpdu), userInfo.nss});
561
562 NS_LOG_DEBUG("Adding STA "
563 << receiver
564 << " to the list of stations that will be solicited by the MU-BAR");
566 acknowledgment->stationsReplyingWithBlockAck.emplace(
567 receiver,
568 WifiDlMuTfMuBar::BlockAckInfo{edca->GetBaManager()->GetBlockAckReqHeader(
569 mpdu->GetOriginal()->GetHeader().GetAddr1(),
570 tid),
571 blockAckTxVector,
572 m_mac->GetBaTypeAsOriginator(receiver, tid)});
573
574 acknowledgment->barTypes.push_back(m_mac->GetBarTypeAsOriginator(receiver, tid));
575 acknowledgment->muBarTxVector = GetWifiRemoteStationManager()->GetRtsTxVector(receiver);
576 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::BLOCK_ACK);
577 return std::unique_ptr<WifiDlMuTfMuBar>(acknowledgment);
578 }
579
580 // an MPDU addressed to the same receiver has been already added
581 NS_ASSERT(acknowledgment);
583 "QoS data frames only can be aggregated when transmitting a DL MU PPDU");
584
585 // no change is needed
586 return nullptr;
587}
588
589std::unique_ptr<WifiAcknowledgment>
591 const WifiTxParameters& txParams)
592{
593 NS_LOG_FUNCTION(this << *mpdu << &txParams);
594 NS_ASSERT(txParams.m_txVector.IsDlMu());
596
597 const WifiMacHeader& hdr = mpdu->GetHeader();
598 Mac48Address receiver = hdr.GetAddr1();
599
600 const WifiTxParameters::PsduInfo* psduInfo = txParams.GetPsduInfo(receiver);
601
602 NS_ASSERT(!txParams.m_acknowledgment ||
604
605 WifiDlMuAggregateTf* acknowledgment = nullptr;
606 if (txParams.m_acknowledgment)
607 {
608 acknowledgment = static_cast<WifiDlMuAggregateTf*>(txParams.m_acknowledgment.get());
609 }
610
611 if (!psduInfo)
612 {
613 // we get here if this is the first MPDU for this receiver.
614 Ptr<ApWifiMac> apMac = DynamicCast<ApWifiMac>(m_mac);
615 NS_ABORT_MSG_IF(!apMac, "HE APs only can send DL MU PPDUs");
616 uint16_t staId = apMac->GetAssociationId(receiver, m_linkId);
617
619 "QoS data frames only can be aggregated when transmitting a "
620 "DL MU PPDU acknowledged via a sequence of BAR and BA frames");
621 uint8_t tid = hdr.GetQosTid();
622
623 // Add the receiver to the list of stations that will reply with a Block Ack
624 if (acknowledgment)
625 {
626 // txParams.m_acknowledgment points to an existing WifiDlMuAggregateTf object.
627 // We have to return a copy of this object including the needed changes
628 acknowledgment = new WifiDlMuAggregateTf(*acknowledgment);
629 }
630 else
631 {
632 // we have to create a new WifiDlMuAggregateTf object
633 acknowledgment = new WifiDlMuAggregateTf;
634 }
635
636 // determine the TX vector used to send the BlockAck frame
637 WifiTxVector blockAckTxVector;
638 auto preamble = IsEht(txParams.m_txVector.GetPreambleType()) ? WIFI_PREAMBLE_EHT_TB
640 blockAckTxVector.SetPreambleType(preamble);
641 blockAckTxVector.SetChannelWidth(txParams.m_txVector.GetChannelWidth());
642 // 800ns GI is not allowed for HE TB
643 blockAckTxVector.SetGuardInterval(
644 std::max<uint16_t>(txParams.m_txVector.GetGuardInterval(), 1600));
645 const auto& userInfo = txParams.m_txVector.GetHeMuUserInfo(staId);
646 blockAckTxVector.SetHeMuUserInfo(
647 staId,
648 {userInfo.ru, std::min(userInfo.mcs, m_maxMcsForBlockAckInTbPpdu), userInfo.nss});
649
650 NS_LOG_DEBUG("Adding STA " << receiver
651 << " to the list of stations that will reply with a Block Ack");
653 acknowledgment->stationsReplyingWithBlockAck.emplace(
654 receiver,
656 GetMuBarSize({m_mac->GetBarTypeAsOriginator(receiver, tid)}),
657 edca->GetBaManager()->GetBlockAckReqHeader(
658 mpdu->GetOriginal()->GetHeader().GetAddr1(),
659 tid),
660 blockAckTxVector,
661 m_mac->GetBaTypeAsOriginator(receiver, tid)});
662
663 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::NO_EXPLICIT_ACK);
664 return std::unique_ptr<WifiDlMuAggregateTf>(acknowledgment);
665 }
666
667 // an MPDU addressed to the same receiver has been already added
668 NS_ASSERT(acknowledgment);
670 !hdr.IsQosData(),
671 "QoS data and MU-BAR Trigger frames only can be aggregated when transmitting a DL MU PPDU");
672
673 // no change is needed
674 return nullptr;
675}
676
677std::unique_ptr<WifiAcknowledgment>
679 const WifiTxParameters& txParams)
680{
681 NS_LOG_FUNCTION(this << *mpdu << &txParams);
682 NS_ASSERT(mpdu->GetHeader().IsTrigger());
683
684 Ptr<ApWifiMac> apMac = DynamicCast<ApWifiMac>(m_mac);
685 NS_ABORT_MSG_IF(!apMac, "HE APs only can send Trigger Frames");
686
687 auto heFem = DynamicCast<HeFrameExchangeManager>(m_mac->GetFrameExchangeManager(m_linkId));
688 NS_ABORT_MSG_IF(!heFem, "HE APs only can send Trigger Frames");
689
690 CtrlTriggerHeader trigger;
691 mpdu->GetPacket()->PeekHeader(trigger);
692
693 if (trigger.IsBasic())
694 {
695 // the only supported ack method for now is through a multi-STA BlockAck frame
696 auto acknowledgment = std::make_unique<WifiUlMuMultiStaBa>();
697
698 for (const auto& userInfo : trigger)
699 {
700 uint16_t aid12 = userInfo.GetAid12();
701
702 if (aid12 == NO_USER_STA_ID)
703 {
704 NS_LOG_INFO("Unallocated RU");
705 continue;
706 }
707 NS_ABORT_MSG_IF(aid12 == 0 || aid12 > 2007, "Allocation of RA-RUs is not supported");
708
709 NS_ASSERT(apMac->GetStaList(m_linkId).find(aid12) != apMac->GetStaList(m_linkId).end());
710 Mac48Address staAddress = apMac->GetStaList(m_linkId).find(aid12)->second;
711
712 // find a TID for which a BA agreement exists with the given originator
713 uint8_t tid = 0;
714 while (tid < 8 && !m_mac->GetBaAgreementEstablishedAsRecipient(staAddress, tid))
715 {
716 tid++;
717 }
718 NS_ASSERT_MSG(tid < 8,
719 "No Block Ack agreement established with originator " << staAddress);
720
721 std::size_t index = acknowledgment->baType.m_bitmapLen.size();
722 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(staAddress, tid),
723 index);
724
725 // we assume the Block Acknowledgment context is used for the multi-STA BlockAck frame
726 // (since it requires the longest TX time due to the presence of a bitmap)
727 acknowledgment->baType.m_bitmapLen.push_back(
728 m_mac->GetBaTypeAsRecipient(staAddress, tid).m_bitmapLen.at(0));
729 }
730
731 uint16_t staId = trigger.begin()->GetAid12();
732 acknowledgment->tbPpduTxVector = trigger.GetHeTbTxVector(staId);
733 acknowledgment->multiStaBaTxVector = GetWifiRemoteStationManager()->GetBlockAckTxVector(
734 apMac->GetStaList(m_linkId).find(staId)->second,
735 acknowledgment->tbPpduTxVector);
736 return acknowledgment;
737 }
738 else if (trigger.IsBsrp())
739 {
740 return std::make_unique<WifiNoAck>();
741 }
742
743 return nullptr;
744}
745
746} // namespace ns3
AttributeValue implementation for Boolean.
Definition: boolean.h:37
Headers for Trigger frames.
Definition: ctrl-headers.h:942
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:42
Hold variables of type enum.
Definition: enum.h:56
an EUI-48 address
Definition: mac48-address.h:46
bool IsGroup() const
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:78
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:936
Hold an unsigned integer type.
Definition: uinteger.h:45
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.
Ptr< FrameExchangeManager > GetFrameExchangeManager(uint8_t linkId=SINGLE_LINK_OP_ID) const
Get the Frame Exchange Manager associated with the given link.
Definition: wifi-mac.cc:864
BlockAckType GetBaTypeAsRecipient(Mac48Address originator, uint8_t tid) const
Definition: wifi-mac.cc:1445
BlockAckType GetBaTypeAsOriginator(const Mac48Address &recipient, uint8_t tid) const
Definition: wifi-mac.cc:1427
virtual Ptr< WifiMacQueue > GetTxopQueue(AcIndex ac) const
Get the wifi MAC queue of the (Qos)Txop associated with the given AC, if such (Qos)Txop is installed,...
Definition: wifi-mac.cc:543
BlockAckReqType GetBarTypeAsOriginator(const Mac48Address &recipient, uint8_t tid) const
Definition: wifi-mac.cc:1436
OriginatorAgreementOptConstRef GetBaAgreementEstablishedAsOriginator(Mac48Address recipient, uint8_t tid) const
Definition: wifi-mac.cc:1405
Ptr< QosTxop > GetQosTxop(AcIndex ac) const
Accessor for a specified EDCA object.
Definition: wifi-mac.cc:497
WifiTxVector GetAckTxVector(Mac48Address to, const WifiTxVector &dataTxVector) const
Return a TXVECTOR for the Ack frame given the destination and the mode of the Data used by the sender...
WifiTxVector GetBlockAckTxVector(Mac48Address to, const WifiTxVector &dataTxVector) const
Return a TXVECTOR for the BlockAck frame given the destination and the mode of the Data used by the s...
WifiTxVector GetRtsTxVector(Mac48Address address)
This class stores the TX parameters (TX vector, protection mechanism, acknowledgment mechanism,...
std::unique_ptr< WifiProtection > m_protection
protection method
uint32_t GetSize(Mac48Address receiver) const
Get the size in bytes of the (A-)MPDU addressed to the given receiver.
std::unique_ptr< WifiAcknowledgment > m_acknowledgment
acknowledgment method
const PsduInfo * GetPsduInfo(Mac48Address receiver) const
Get a pointer to the information about the PSDU addressed to the given receiver, if present,...
WifiTxVector m_txVector
TXVECTOR of the frame being prepared.
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
uint16_t GetGuardInterval() const
void SetChannelWidth(uint16_t channelWidth)
Sets the selected channelWidth (in MHz)
void SetGuardInterval(uint16_t guardInterval)
Sets the guard interval duration (in nanoseconds)
void SetHeMuUserInfo(uint16_t staId, HeMuUserInfo userInfo)
Set the HE MU user-specific transmission information for the given STA-ID.
WifiPreamble GetPreambleType() const
HeMuUserInfo GetHeMuUserInfo(uint16_t staId) const
Get the HE MU user-specific transmission information for the given STA-ID.
bool IsDlMu() const
bool IsUlMu() const
uint16_t GetChannelWidth() 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:66
#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:86
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Definition: boolean.h:86
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition: boolean.cc:124
Ptr< const AttributeAccessor > MakeDoubleAccessor(T1 a1)
Definition: double.h:43
Ptr< const AttributeAccessor > MakeEnumAccessor(T1 a1)
Definition: enum.h:205
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Definition: uinteger.h:46
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition: abort.h:49
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#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:275
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:46
AcIndex QosUtilsMapTidToAc(uint8_t tid)
Maps TID (Traffic ID) to Access classes.
Definition: qos-utils.cc:134
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:182
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:191
@ WIFI_PREAMBLE_EHT_TB
@ WIFI_PREAMBLE_HE_TB
Every class exported by the ns3 library is enclosed in the ns3 namespace.
static constexpr uint16_t SEQNO_SPACE_HALF_SIZE
Size of the half the space of sequence numbers (used to determine old packets)
Definition: wifi-utils.h:136
bool IsEht(WifiPreamble preamble)
Return true if a preamble corresponds to an EHT transmission.
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:86
static constexpr uint16_t SEQNO_SPACE_SIZE
Size of the space of sequence numbers.
Definition: wifi-utils.h:133
Ptr< const AttributeChecker > MakeEnumChecker(int v, std::string n, Ts... args)
Make an EnumChecker pre-configured with a set of allowed values by name.
Definition: enum.h:163
std::vector< uint8_t > m_bitmapLen
Length (bytes) of included bitmaps.
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.
information about the frame being prepared for a specific receiver
std::map< uint8_t, std::set< uint16_t > > seqNumbers
set of the sequence numbers of the MPDUs added for each TID