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(
64 "DlMuAckSequenceType",
65 "Type of the acknowledgment sequence for DL MU PPDUs.",
67 MakeEnumAccessor<WifiAcknowledgment::Method>(&WifiDefaultAckManager::m_dlMuAckType),
69 "DL_MU_BAR_BA_SEQUENCE",
71 "DL_MU_TF_MU_BAR",
73 "DL_MU_AGGREGATE_TF"))
74 .AddAttribute("MaxBlockAckMcs",
75 "The MCS used to send a BlockAck in a TB PPDU is the minimum between "
76 "the MCS used for the PSDU sent in the preceding DL MU PPDU and the "
77 "value of this attribute.",
80 MakeUintegerChecker<uint8_t>(0, 11));
81 return tid;
82}
83
85{
86 NS_LOG_FUNCTION(this);
87}
88
90{
92}
93
94uint16_t
96 const WifiTxParameters& txParams) const
97{
98 NS_LOG_FUNCTION(this << *mpdu << &txParams);
99
100 auto receiver = mpdu->GetHeader().GetAddr1();
101 auto origReceiver = mpdu->GetOriginal()->GetHeader().GetAddr1();
102
103 uint8_t tid = mpdu->GetHeader().GetQosTid();
104 Ptr<QosTxop> edca = m_mac->GetQosTxop(tid);
106 "An established Block Ack agreement is required");
107
108 uint16_t startingSeq = edca->GetBaStartingSequence(origReceiver, tid);
109 uint16_t maxDistFromStartingSeq =
110 (mpdu->GetHeader().GetSequenceNumber() - startingSeq + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE;
111 NS_ABORT_MSG_IF(maxDistFromStartingSeq >= SEQNO_SPACE_HALF_SIZE,
112 "The given QoS data frame is too old");
113
114 const auto* psduInfo = txParams.GetPsduInfo(receiver);
115
116 NS_ASSERT_MSG(psduInfo && psduInfo->seqNumbers.contains(tid),
117 "There must be at least an MPDU with tid " << +tid);
118
119 for (const auto& seqNumber : psduInfo->seqNumbers.at(tid))
120 {
121 if (!QosUtilsIsOldPacket(startingSeq, seqNumber))
122 {
123 uint16_t currDistToStartingSeq =
124 (seqNumber - startingSeq + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE;
125
126 if (currDistToStartingSeq > maxDistFromStartingSeq)
127 {
128 maxDistFromStartingSeq = currDistToStartingSeq;
129 }
130 }
131 }
132
133 NS_LOG_DEBUG("Returning " << maxDistFromStartingSeq);
134 return maxDistFromStartingSeq;
135}
136
137bool
139 const WifiTxParameters& txParams) const
140{
141 NS_LOG_FUNCTION(this << *mpdu << &txParams);
142
143 uint8_t tid = mpdu->GetHeader().GetQosTid();
144 Mac48Address receiver = mpdu->GetOriginal()->GetHeader().GetAddr1();
145 Ptr<QosTxop> edca = m_mac->GetQosTxop(tid);
146
147 // An immediate response (Ack or Block Ack) is needed if any of the following holds:
148 // * the maximum distance between the sequence number of an MPDU to transmit
149 // and the starting sequence number of the transmit window is greater than
150 // or equal to the window size multiplied by the BaThreshold
151 // * no other frame belonging to this BA agreement is queued (because, in such
152 // a case, a Block Ack is not going to be requested anytime soon)
153 // * this is the initial frame of a transmission opportunity and it is not
154 // protected by RTS/CTS (see Annex G.3 of IEEE 802.11-2016)
155 return !(
156 m_baThreshold > 0 &&
157 GetMaxDistFromStartingSeq(mpdu, txParams) <
158 m_baThreshold * edca->GetBaBufferSize(receiver, tid) &&
159 (edca->GetWifiMacQueue()->GetNPackets({WIFI_QOSDATA_QUEUE, WIFI_UNICAST, receiver, tid}) -
160 edca->GetBaManager()->GetNBufferedPackets(receiver, tid) >
161 1) &&
162 !(edca->GetTxopLimit(m_linkId).IsStrictlyPositive() &&
163 edca->GetRemainingTxop(m_linkId) == edca->GetTxopLimit(m_linkId) &&
164 !(txParams.m_protection && txParams.m_protection->method == WifiProtection::RTS_CTS)));
165}
166
167bool
169{
170 NS_ASSERT(mpdu->GetHeader().IsQosData());
171 auto tid = mpdu->GetHeader().GetQosTid();
172 NS_ASSERT(mpdu->IsQueued());
173 auto queue = m_mac->GetTxopQueue(mpdu->GetQueueAc());
174 auto origReceiver = mpdu->GetOriginal()->GetHeader().GetAddr1();
175 auto agreement = m_mac->GetBaAgreementEstablishedAsOriginator(origReceiver, tid);
176 NS_ASSERT(agreement);
177 auto mpduDist = agreement->get().GetDistance(mpdu->GetHeader().GetSequenceNumber());
178
179 Ptr<WifiMpdu> item = queue->PeekByTidAndAddress(tid, origReceiver);
180
181 while (item)
182 {
183 auto itemDist = agreement->get().GetDistance(item->GetHeader().GetSequenceNumber());
184 if (itemDist == mpduDist)
185 {
186 NS_LOG_DEBUG("No previous MPDU in-flight on the same link");
187 return false;
188 }
189 NS_ABORT_MSG_IF(itemDist > mpduDist,
190 "While searching for given MPDU ("
191 << *mpdu << "), found first another one (" << *item
192 << ") with higher sequence number");
193 if (auto linkIds = item->GetInFlightLinkIds(); linkIds.contains(m_linkId))
194 {
195 NS_LOG_DEBUG("Found MPDU inflight on the same link");
196 return true;
197 }
198 item = queue->PeekByTidAndAddress(tid, origReceiver, item);
199 }
200 NS_ABORT_MSG("Should not get here");
201 return false;
202}
203
204std::unique_ptr<WifiAcknowledgment>
206{
207 NS_LOG_FUNCTION(this << *mpdu << &txParams);
208
209 // If the TXVECTOR indicates a DL MU PPDU, call a separate method
210 if (txParams.m_txVector.IsDlMu())
211 {
212 switch (m_dlMuAckType)
213 {
215 return GetAckInfoIfBarBaSequence(mpdu, txParams);
217 return GetAckInfoIfTfMuBar(mpdu, txParams);
219 return GetAckInfoIfAggregatedMuBar(mpdu, txParams);
220 default:
221 NS_ABORT_MSG("Unknown DL acknowledgment method");
222 return nullptr;
223 }
224 }
225
226 const WifiMacHeader& hdr = mpdu->GetHeader();
227 Mac48Address receiver = hdr.GetAddr1();
228
229 // Acknowledgment for TB PPDUs
230 if (txParams.m_txVector.IsUlMu())
231 {
232 if (hdr.IsQosData() && !hdr.HasData())
233 {
234 // QoS Null frame
235 std::unique_ptr<WifiAcknowledgment> acknowledgment;
236
237 if (txParams.m_acknowledgment)
238 {
240 acknowledgment = txParams.m_acknowledgment->Copy();
241 }
242 else
243 {
244 acknowledgment = std::make_unique<WifiNoAck>();
245 }
246 acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::NO_ACK);
247 return acknowledgment;
248 }
249
250 if (txParams.m_acknowledgment)
251 {
253 return nullptr;
254 }
255
256 auto acknowledgment = std::make_unique<WifiAckAfterTbPpdu>();
257 if (hdr.IsQosData())
258 {
259 acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::NORMAL_ACK);
260 }
261 return acknowledgment;
262 }
263
264 // if this is a Trigger Frame, call a separate method
265 if (hdr.IsTrigger())
266 {
267 return TryUlMuTransmission(mpdu, txParams);
268 }
269
270 // if the current acknowledgment method (if any) is already BLOCK_ACK, it will not
271 // change by adding an MPDU
272 if (txParams.m_acknowledgment &&
274 {
275 return nullptr;
276 }
277
278 if (receiver.IsGroup())
279 {
280 NS_ABORT_MSG_IF(!txParams.LastAddedIsFirstMpdu(receiver),
281 "Unicast frames only can be aggregated");
282 auto acknowledgment = std::make_unique<WifiNoAck>();
283 if (hdr.IsQosData())
284 {
285 acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::NO_ACK);
286 }
287 return acknowledgment;
288 }
289
290 if ((!hdr.IsQosData() ||
292 !hdr.IsBlockAckReq())
293 {
295 "Non-QoS data frame or Block Ack agreement not established, request Normal Ack");
296 auto acknowledgment = std::make_unique<WifiNormalAck>();
297 acknowledgment->ackTxVector =
298 GetWifiRemoteStationManager()->GetAckTxVector(receiver, txParams.m_txVector);
299 if (hdr.IsQosData())
300 {
301 acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::NORMAL_ACK);
302 }
303 return acknowledgment;
304 }
305
306 // we get here if mpdu is a QoS data frame related to an established Block Ack agreement
307 // or mpdu is a BlockAckReq frame
308 if (!hdr.IsBlockAckReq() && !IsResponseNeeded(mpdu, txParams))
309 {
310 NS_LOG_DEBUG("A response is not needed: no ack for now, use Block Ack policy");
311 if (txParams.m_acknowledgment &&
312 txParams.m_acknowledgment->method == WifiAcknowledgment::NONE)
313 {
314 // no change if the ack method is already NONE
315 return nullptr;
316 }
317
318 auto acknowledgment = std::make_unique<WifiNoAck>();
319 if (hdr.IsQosData())
320 {
321 acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::BLOCK_ACK);
322 }
323 return acknowledgment;
324 }
325
326 // we get here if a response is needed
327 uint8_t tid = GetTid(mpdu->GetPacket(), hdr);
328 if (!hdr.IsBlockAckReq() && txParams.LastAddedIsFirstMpdu(receiver) &&
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 =
334 GetWifiRemoteStationManager()->GetAckTxVector(receiver, txParams.m_txVector);
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.LastAddedIsFirstMpdu(receiver) || 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 =
349 GetWifiRemoteStationManager()->GetBlockAckTxVector(receiver, txParams.m_txVector);
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 =
361 GetWifiRemoteStationManager()->GetBlockAckTxVector(receiver, txParams.m_txVector);
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
388 "QoS data frames only can be aggregated when transmitting a "
389 "DL MU PPDU acknowledged via a sequence of BAR and BA frames");
390 uint8_t tid = hdr.GetQosTid();
392
393 NS_ASSERT(!txParams.m_acknowledgment ||
395
396 WifiDlMuBarBaSequence* acknowledgment = nullptr;
397 if (txParams.m_acknowledgment)
398 {
399 acknowledgment = static_cast<WifiDlMuBarBaSequence*>(txParams.m_acknowledgment.get());
400 }
401
402 if (!txParams.LastAddedIsFirstMpdu(receiver))
403 {
404 // an MPDU addressed to the same receiver has been already added
405 NS_ASSERT(acknowledgment);
406
407 if (acknowledgment->stationsSendBlockAckReqTo.contains(receiver) ||
408 acknowledgment->stationsReplyingWithBlockAck.contains(receiver))
409 {
410 // the receiver either is already listed among the stations that will
411 // receive a BlockAckReq frame or is the station that will immediately
412 // respond with a BlockAck frame, hence no change is needed
413 return nullptr;
414 }
415
416 // the receiver was scheduled for responding immediately with a Normal Ack.
417 // Given that we are adding an MPDU, the receiver must be scheduled for
418 // responding immediately with a Block Ack
419 NS_ASSERT(acknowledgment->stationsReplyingWithNormalAck.size() == 1 &&
420 acknowledgment->stationsReplyingWithNormalAck.begin()->first == receiver);
421
422 // acknowledgment points to the m_acknowledgment member of txParams, which is
423 // passed as const reference because it must not be modified. Therefore, we
424 // make a copy of the object pointed to by acknowledgment and make changes to
425 // the copy
426 acknowledgment = new WifiDlMuBarBaSequence(*acknowledgment);
427 acknowledgment->stationsReplyingWithNormalAck.clear();
428
429 acknowledgment->stationsReplyingWithBlockAck.emplace(
430 receiver,
432 GetWifiRemoteStationManager()->GetBlockAckTxVector(receiver, txParams.m_txVector),
433 m_mac->GetBaTypeAsOriginator(receiver, tid)});
434 return std::unique_ptr<WifiDlMuBarBaSequence>(acknowledgment);
435 }
436
437 // we get here if this is the first MPDU for this receiver
438 auto htFem = DynamicCast<HtFrameExchangeManager>(m_mac->GetFrameExchangeManager(m_linkId));
439 NS_ASSERT(htFem);
440 if (auto bar = htFem->GetBar(QosUtilsMapTidToAc(tid), tid, receiver);
441 bar || (acknowledgment && (!acknowledgment->stationsReplyingWithNormalAck.empty() ||
442 !acknowledgment->stationsReplyingWithBlockAck.empty())))
443 {
444 // there is a pending BlockAckReq for this receiver or another receiver
445 // was selected for immediate response.
446 // Add this receiver to the list of stations receiving a BlockAckReq.
447 if (acknowledgment)
448 {
449 // txParams.m_acknowledgment points to an existing WifiDlMuBarBaSequence object.
450 // We have to return a copy of this object including the needed changes
451 acknowledgment = new WifiDlMuBarBaSequence(*acknowledgment);
452 }
453 else
454 {
455 // we have to create a new WifiDlMuBarBaSequence object
456 acknowledgment = new WifiDlMuBarBaSequence;
457 }
458
459 NS_LOG_DEBUG("Adding STA " << receiver
460 << " to the list of stations receiving a BlockAckReq");
461 acknowledgment->stationsSendBlockAckReqTo.emplace(
462 receiver,
464 GetWifiRemoteStationManager()->GetBlockAckTxVector(receiver, txParams.m_txVector),
465 m_mac->GetBarTypeAsOriginator(receiver, tid),
466 GetWifiRemoteStationManager()->GetBlockAckTxVector(receiver, txParams.m_txVector),
467 m_mac->GetBaTypeAsOriginator(receiver, tid)});
468
469 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::BLOCK_ACK);
470 return std::unique_ptr<WifiDlMuBarBaSequence>(acknowledgment);
471 }
472
473 // Add the receiver as the station that will immediately reply with a Normal Ack
474 if (acknowledgment)
475 {
476 // txParams.m_acknowledgment points to an existing WifiDlMuBarBaSequence object.
477 // We have to return a copy of this object including the needed changes
478 acknowledgment = new WifiDlMuBarBaSequence(*acknowledgment);
479 }
480 else
481 {
482 // we have to create a new WifiDlMuBarBaSequence object
483 acknowledgment = new WifiDlMuBarBaSequence;
484 }
485
486 NS_LOG_DEBUG("Adding STA " << receiver
487 << " as the station that will immediately reply with a Normal Ack");
488 acknowledgment->stationsReplyingWithNormalAck.emplace(
489 receiver,
491 GetWifiRemoteStationManager()->GetAckTxVector(receiver, txParams.m_txVector)});
492
493 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::NORMAL_ACK);
494 return std::unique_ptr<WifiDlMuBarBaSequence>(acknowledgment);
495}
496
497std::unique_ptr<WifiAcknowledgment>
499 const WifiTxParameters& txParams)
500{
501 NS_LOG_FUNCTION(this << *mpdu << &txParams);
502 NS_ASSERT(txParams.m_txVector.IsDlMu());
504
505 const WifiMacHeader& hdr = mpdu->GetHeader();
506 Mac48Address receiver = hdr.GetAddr1();
507
508 NS_ASSERT(!txParams.m_acknowledgment ||
510
511 WifiDlMuTfMuBar* acknowledgment = nullptr;
512 if (txParams.m_acknowledgment)
513 {
514 acknowledgment = static_cast<WifiDlMuTfMuBar*>(txParams.m_acknowledgment.get());
515 }
516
517 if (txParams.LastAddedIsFirstMpdu(receiver))
518 {
519 // we get here if this is the first MPDU for this receiver.
520 Ptr<ApWifiMac> apMac = DynamicCast<ApWifiMac>(m_mac);
521 NS_ABORT_MSG_IF(!apMac, "HE APs only can send DL MU PPDUs");
522 uint16_t staId = apMac->GetAssociationId(receiver, m_linkId);
523
525 "QoS data frames only can be aggregated when transmitting a "
526 "DL MU PPDU acknowledged via a MU-BAR sent as SU frame");
527 uint8_t tid = hdr.GetQosTid();
528
529 // Add the receiver to the list of stations that will reply with a Block Ack
530 if (acknowledgment)
531 {
532 // txParams.m_acknowledgment points to an existing WifiDlMuTfMuBar object.
533 // We have to return a copy of this object including the needed changes
534 acknowledgment = new WifiDlMuTfMuBar(*acknowledgment);
535 }
536 else
537 {
538 // we have to create a new WifiDlMuTfMuBar object
539 acknowledgment = new WifiDlMuTfMuBar;
540 }
541
542 // determine the TX vector used to send the BlockAck frame
543 WifiTxVector blockAckTxVector;
544 auto preamble = IsEht(txParams.m_txVector.GetPreambleType()) ? WIFI_PREAMBLE_EHT_TB
546 blockAckTxVector.SetPreambleType(preamble);
547 blockAckTxVector.SetChannelWidth(txParams.m_txVector.GetChannelWidth());
548 // 800ns GI is not allowed for HE TB
549 blockAckTxVector.SetGuardInterval(
550 std::max<uint16_t>(txParams.m_txVector.GetGuardInterval(), 1600));
551 const auto& userInfo = txParams.m_txVector.GetHeMuUserInfo(staId);
552 blockAckTxVector.SetHeMuUserInfo(
553 staId,
554 {userInfo.ru, std::min(userInfo.mcs, m_maxMcsForBlockAckInTbPpdu), userInfo.nss});
555
556 NS_LOG_DEBUG("Adding STA "
557 << receiver
558 << " to the list of stations that will be solicited by the MU-BAR");
560 acknowledgment->stationsReplyingWithBlockAck.emplace(
561 receiver,
562 WifiDlMuTfMuBar::BlockAckInfo{edca->GetBaManager()->GetBlockAckReqHeader(
563 mpdu->GetOriginal()->GetHeader().GetAddr1(),
564 tid),
565 blockAckTxVector,
566 m_mac->GetBaTypeAsOriginator(receiver, tid)});
567
568 acknowledgment->barTypes.push_back(m_mac->GetBarTypeAsOriginator(receiver, tid));
569 acknowledgment->muBarTxVector =
570 GetWifiRemoteStationManager()->GetRtsTxVector(receiver,
571 txParams.m_txVector.GetChannelWidth());
572 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::BLOCK_ACK);
573 return std::unique_ptr<WifiDlMuTfMuBar>(acknowledgment);
574 }
575
576 // an MPDU addressed to the same receiver has been already added
577 NS_ASSERT(acknowledgment);
579 "QoS data frames only can be aggregated when transmitting a DL MU PPDU");
580
581 // no change is needed
582 return nullptr;
583}
584
585std::unique_ptr<WifiAcknowledgment>
587 const WifiTxParameters& txParams)
588{
589 NS_LOG_FUNCTION(this << *mpdu << &txParams);
590 NS_ASSERT(txParams.m_txVector.IsDlMu());
592
593 const WifiMacHeader& hdr = mpdu->GetHeader();
594 Mac48Address receiver = hdr.GetAddr1();
595
596 NS_ASSERT(!txParams.m_acknowledgment ||
598
599 WifiDlMuAggregateTf* acknowledgment = nullptr;
600 if (txParams.m_acknowledgment)
601 {
602 acknowledgment = static_cast<WifiDlMuAggregateTf*>(txParams.m_acknowledgment.get());
603 }
604
605 if (txParams.LastAddedIsFirstMpdu(receiver))
606 {
607 // we get here if this is the first MPDU for this receiver.
608 Ptr<ApWifiMac> apMac = DynamicCast<ApWifiMac>(m_mac);
609 NS_ABORT_MSG_IF(!apMac, "HE APs only can send DL MU PPDUs");
610 uint16_t staId = apMac->GetAssociationId(receiver, m_linkId);
611
613 "QoS data frames only can be aggregated when transmitting a "
614 "DL MU PPDU acknowledged via a sequence of BAR and BA frames");
615 uint8_t tid = hdr.GetQosTid();
616
617 // Add the receiver to the list of stations that will reply with a Block Ack
618 if (acknowledgment)
619 {
620 // txParams.m_acknowledgment points to an existing WifiDlMuAggregateTf object.
621 // We have to return a copy of this object including the needed changes
622 acknowledgment = new WifiDlMuAggregateTf(*acknowledgment);
623 }
624 else
625 {
626 // we have to create a new WifiDlMuAggregateTf object
627 acknowledgment = new WifiDlMuAggregateTf;
628 }
629
630 // determine the TX vector used to send the BlockAck frame
631 WifiTxVector blockAckTxVector;
632 auto preamble = IsEht(txParams.m_txVector.GetPreambleType()) ? WIFI_PREAMBLE_EHT_TB
634 blockAckTxVector.SetPreambleType(preamble);
635 blockAckTxVector.SetChannelWidth(txParams.m_txVector.GetChannelWidth());
636 // 800ns GI is not allowed for HE TB
637 blockAckTxVector.SetGuardInterval(
638 std::max<uint16_t>(txParams.m_txVector.GetGuardInterval(), 1600));
639 const auto& userInfo = txParams.m_txVector.GetHeMuUserInfo(staId);
640 blockAckTxVector.SetHeMuUserInfo(
641 staId,
642 {userInfo.ru, std::min(userInfo.mcs, m_maxMcsForBlockAckInTbPpdu), userInfo.nss});
643
644 NS_LOG_DEBUG("Adding STA " << receiver
645 << " to the list of stations that will reply with a Block Ack");
647 acknowledgment->stationsReplyingWithBlockAck.emplace(
648 receiver,
650 GetMuBarSize({m_mac->GetBarTypeAsOriginator(receiver, tid)}),
651 edca->GetBaManager()->GetBlockAckReqHeader(
652 mpdu->GetOriginal()->GetHeader().GetAddr1(),
653 tid),
654 blockAckTxVector,
655 m_mac->GetBaTypeAsOriginator(receiver, tid)});
656
657 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::NO_EXPLICIT_ACK);
658 return std::unique_ptr<WifiDlMuAggregateTf>(acknowledgment);
659 }
660
661 // an MPDU addressed to the same receiver has been already added
662 NS_ASSERT(acknowledgment);
664 !hdr.IsQosData(),
665 "QoS data and MU-BAR Trigger frames only can be aggregated when transmitting a DL MU PPDU");
666
667 // no change is needed
668 return nullptr;
669}
670
671std::unique_ptr<WifiAcknowledgment>
673 const WifiTxParameters& txParams)
674{
675 NS_LOG_FUNCTION(this << *mpdu << &txParams);
676 NS_ASSERT(mpdu->GetHeader().IsTrigger());
677
678 Ptr<ApWifiMac> apMac = DynamicCast<ApWifiMac>(m_mac);
679 NS_ABORT_MSG_IF(!apMac, "HE APs only can send Trigger Frames");
680
681 auto heFem = DynamicCast<HeFrameExchangeManager>(m_mac->GetFrameExchangeManager(m_linkId));
682 NS_ABORT_MSG_IF(!heFem, "HE APs only can send Trigger Frames");
683
684 CtrlTriggerHeader trigger;
685 mpdu->GetPacket()->PeekHeader(trigger);
686
687 if (trigger.IsBasic())
688 {
689 // the only supported ack method for now is through a multi-STA BlockAck frame
690 auto acknowledgment = std::make_unique<WifiUlMuMultiStaBa>();
691
692 for (const auto& userInfo : trigger)
693 {
694 uint16_t aid12 = userInfo.GetAid12();
695
696 if (aid12 == NO_USER_STA_ID)
697 {
698 NS_LOG_INFO("Unallocated RU");
699 continue;
700 }
701 NS_ABORT_MSG_IF(aid12 == 0 || aid12 > 2007, "Allocation of RA-RUs is not supported");
702
703 const auto it = apMac->GetStaList(m_linkId).find(aid12);
704 NS_ASSERT(it != apMac->GetStaList(m_linkId).end());
705 const auto staAddress = it->second;
706
707 // find a TID for which a BA agreement exists with the given originator
708 uint8_t tid = 0;
709 while (tid < 8 && !m_mac->GetBaAgreementEstablishedAsRecipient(staAddress, tid))
710 {
711 tid++;
712 }
713 NS_ASSERT_MSG(tid < 8,
714 "No Block Ack agreement established with originator " << staAddress);
715
716 std::size_t index = acknowledgment->baType.m_bitmapLen.size();
717 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(staAddress, tid),
718 index);
719
720 // we assume the Block Acknowledgment context is used for the multi-STA BlockAck frame
721 // (since it requires the longest TX time due to the presence of a bitmap)
722 acknowledgment->baType.m_bitmapLen.push_back(
723 m_mac->GetBaTypeAsRecipient(staAddress, tid).m_bitmapLen.at(0));
724 }
725
726 uint16_t staId = trigger.begin()->GetAid12();
727 acknowledgment->tbPpduTxVector = trigger.GetHeTbTxVector(staId);
728 acknowledgment->multiStaBaTxVector = GetWifiRemoteStationManager()->GetBlockAckTxVector(
729 apMac->GetStaList(m_linkId).find(staId)->second,
730 acknowledgment->tbPpduTxVector);
731 return acknowledgment;
732 }
733 else if (trigger.IsBsrp())
734 {
735 return std::make_unique<WifiNoAck>();
736 }
737
738 return nullptr;
739}
740
741} // namespace ns3
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:62
an EUI-48 address
Definition: mac48-address.h:46
bool IsGroup() const
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:932
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:981
BlockAckType GetBaTypeAsRecipient(Mac48Address originator, uint8_t tid) const
Definition: wifi-mac.cc:1861
BlockAckType GetBaTypeAsOriginator(const Mac48Address &recipient, uint8_t tid) const
Definition: wifi-mac.cc:1843
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:639
BlockAckReqType GetBarTypeAsOriginator(const Mac48Address &recipient, uint8_t tid) const
Definition: wifi-mac.cc:1852
OriginatorAgreementOptConstRef GetBaAgreementEstablishedAsOriginator(Mac48Address recipient, uint8_t tid) const
Definition: wifi-mac.cc:1821
Ptr< QosTxop > GetQosTxop(AcIndex ac) const
Accessor for a specified EDCA object.
Definition: wifi-mac.cc:593
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...
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
#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.
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition: boolean.cc:124
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:189
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Definition: uinteger.h:46
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:189
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:88
static constexpr uint16_t SEQNO_SPACE_SIZE
Size of the space of sequence numbers.
Definition: wifi-utils.h:186
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Definition: boolean.h:81
Ptr< const AttributeAccessor > MakeDoubleAccessor(T1 a1)
Definition: double.h:43
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.