A Discrete-Event Network Simulator
API
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/he-phy.h"
32#include "ns3/log.h"
33
34namespace ns3
35{
36
37NS_LOG_COMPONENT_DEFINE("WifiDefaultAckManager");
38
39NS_OBJECT_ENSURE_REGISTERED(WifiDefaultAckManager);
40
41TypeId
43{
44 static TypeId tid =
45 TypeId("ns3::WifiDefaultAckManager")
47 .SetGroupName("Wifi")
48 .AddConstructor<WifiDefaultAckManager>()
49 .AddAttribute("UseExplicitBar",
50 "Specify whether to send Block Ack Requests (if true) or use"
51 " Implicit Block Ack Request ack policy (if false).",
52 BooleanValue(false),
55 .AddAttribute("BaThreshold",
56 "Immediate acknowledgment is requested upon transmission of a frame "
57 "whose sequence number is distant at least BaThreshold multiplied "
58 "by the transmit window size from the starting sequence number of "
59 "the transmit window. Set to zero to request a response for every "
60 "transmitted frame.",
61 DoubleValue(0.0),
63 MakeDoubleChecker<double>(0.0, 1.0))
64 .AddAttribute("DlMuAckSequenceType",
65 "Type of the acknowledgment sequence for DL MU PPDUs.",
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 const WifiMacHeader& hdr = mpdu->GetHeader();
101 Mac48Address receiver = hdr.GetAddr1();
102
103 uint8_t tid = hdr.GetQosTid();
104 Ptr<QosTxop> edca = m_mac->GetQosTxop(tid);
105 NS_ABORT_MSG_IF(!edca->GetBaAgreementEstablished(receiver, tid),
106 "An established Block Ack agreement is required");
107
108 uint16_t startingSeq = edca->GetBaStartingSequence(receiver, 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 WifiTxParameters::PsduInfo* psduInfo = txParams.GetPsduInfo(receiver);
115
116 if (!psduInfo || psduInfo->seqNumbers.find(tid) == psduInfo->seqNumbers.end())
117 {
118 // there are no aggregated MPDUs (so far)
119 return maxDistFromStartingSeq;
120 }
121
122 for (const auto& seqNumber : psduInfo->seqNumbers.at(tid))
123 {
124 if (!QosUtilsIsOldPacket(startingSeq, seqNumber))
125 {
126 uint16_t currDistToStartingSeq =
127 (seqNumber - startingSeq + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE;
128
129 if (currDistToStartingSeq > maxDistFromStartingSeq)
130 {
131 maxDistFromStartingSeq = currDistToStartingSeq;
132 }
133 }
134 }
135
136 NS_LOG_DEBUG("Returning " << maxDistFromStartingSeq);
137 return maxDistFromStartingSeq;
138}
139
140bool
142 const WifiTxParameters& txParams) const
143{
144 NS_LOG_FUNCTION(this << *mpdu << &txParams);
145
146 uint8_t tid = mpdu->GetHeader().GetQosTid();
147 Mac48Address receiver = mpdu->GetHeader().GetAddr1();
148 Ptr<QosTxop> edca = m_mac->GetQosTxop(tid);
149
150 // An immediate response (Ack or Block Ack) is needed if any of the following holds:
151 // * the maximum distance between the sequence number of an MPDU to transmit
152 // and the starting sequence number of the transmit window is greater than
153 // or equal to the window size multiplied by the BaThreshold
154 // * no other frame belonging to this BA agreement is queued (because, in such
155 // a case, a Block Ack is not going to be requested anytime soon)
156 // * this is the initial frame of a transmission opportunity and it is not
157 // protected by RTS/CTS (see Annex G.3 of IEEE 802.11-2016)
158 if (m_baThreshold > 0 &&
159 GetMaxDistFromStartingSeq(mpdu, txParams) <
160 m_baThreshold * edca->GetBaBufferSize(receiver, tid) &&
161 (edca->GetWifiMacQueue()->GetNPackets({WIFI_QOSDATA_UNICAST_QUEUE, receiver, tid}) -
162 edca->GetBaManager()->GetNBufferedPackets(receiver, tid) >
163 1) &&
166 !(txParams.m_protection && txParams.m_protection->method == WifiProtection::RTS_CTS)))
167 {
168 return false;
169 }
170
171 return true;
172}
173
174std::unique_ptr<WifiAcknowledgment>
176{
177 NS_LOG_FUNCTION(this << *mpdu << &txParams);
178
179 // If the TXVECTOR indicates a DL MU PPDU, call a separate method
180 if (txParams.m_txVector.IsDlMu())
181 {
182 switch (m_dlMuAckType)
183 {
185 return GetAckInfoIfBarBaSequence(mpdu, txParams);
187 return GetAckInfoIfTfMuBar(mpdu, txParams);
189 return GetAckInfoIfAggregatedMuBar(mpdu, txParams);
190 default:
191 NS_ABORT_MSG("Unknown DL acknowledgment method");
192 return nullptr;
193 }
194 }
195
196 const WifiMacHeader& hdr = mpdu->GetHeader();
197 Mac48Address receiver = hdr.GetAddr1();
198
199 // Acknowledgment for TB PPDUs
200 if (txParams.m_txVector.IsUlMu())
201 {
202 if (hdr.IsQosData() && !hdr.HasData())
203 {
204 // QoS Null frame
205 WifiNoAck* acknowledgment = nullptr;
206
207 if (txParams.m_acknowledgment)
208 {
210 acknowledgment = static_cast<WifiNoAck*>(txParams.m_acknowledgment.get());
211 acknowledgment = new WifiNoAck(*acknowledgment);
212 }
213 else
214 {
215 acknowledgment = new WifiNoAck;
216 }
217 acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::NO_ACK);
218 return std::unique_ptr<WifiAcknowledgment>(acknowledgment);
219 }
220
221 if (txParams.m_acknowledgment)
222 {
224 return nullptr;
225 }
226
227 WifiAckAfterTbPpdu* acknowledgment = new WifiAckAfterTbPpdu;
228 if (hdr.IsQosData())
229 {
230 acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::NORMAL_ACK);
231 }
232 return std::unique_ptr<WifiAcknowledgment>(acknowledgment);
233 }
234
235 // if this is a Trigger Frame, call a separate method
236 if (hdr.IsTrigger())
237 {
238 return TryUlMuTransmission(mpdu, txParams);
239 }
240
241 // if the current protection method (if any) is already BLOCK_ACK or BAR_BLOCK_ACK,
242 // it will not change by adding an MPDU
243 if (txParams.m_acknowledgment &&
244 (txParams.m_acknowledgment->method == WifiAcknowledgment::BLOCK_ACK ||
246 {
247 return nullptr;
248 }
249
250 if (receiver.IsGroup())
251 {
252 NS_ABORT_MSG_IF(txParams.GetSize(receiver) > 0, "Unicast frames only can be aggregated");
253 WifiNoAck* acknowledgment = new WifiNoAck;
254 if (hdr.IsQosData())
255 {
256 acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::NO_ACK);
257 }
258 return std::unique_ptr<WifiAcknowledgment>(acknowledgment);
259 }
260
261 if ((!hdr.IsQosData() || !m_mac->GetQosTxop(hdr.GetQosTid())
262 ->GetBaAgreementEstablished(receiver, hdr.GetQosTid())) &&
263 !hdr.IsBlockAckReq())
264 {
266 "Non-QoS data frame or Block Ack agreement not established, request Normal Ack");
267 WifiNormalAck* acknowledgment = new WifiNormalAck;
268 acknowledgment->ackTxVector =
270 if (hdr.IsQosData())
271 {
272 acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::NORMAL_ACK);
273 }
274 return std::unique_ptr<WifiAcknowledgment>(acknowledgment);
275 }
276
277 // we get here if mpdu is a QoS data frame related to an established Block Ack agreement
278 // or mpdu is a BlockAckReq frame
279 if (!hdr.IsBlockAckReq() && !IsResponseNeeded(mpdu, txParams))
280 {
281 NS_LOG_DEBUG("A response is not needed: no ack for now, use Block Ack policy");
282 if (txParams.m_acknowledgment &&
283 txParams.m_acknowledgment->method == WifiAcknowledgment::NONE)
284 {
285 // no change if the ack method is already NONE
286 return nullptr;
287 }
288
289 WifiNoAck* acknowledgment = new WifiNoAck;
290 if (hdr.IsQosData())
291 {
292 acknowledgment->SetQosAckPolicy(receiver, hdr.GetQosTid(), WifiMacHeader::BLOCK_ACK);
293 }
294 return std::unique_ptr<WifiAcknowledgment>(acknowledgment);
295 }
296
297 // we get here if a response is needed
298 uint8_t tid = GetTid(mpdu->GetPacket(), hdr);
299 if (!hdr.IsBlockAckReq() && txParams.GetSize(receiver) == 0 &&
300 hdr.GetSequenceNumber() == m_mac->GetQosTxop(tid)->GetBaStartingSequence(receiver, tid))
301 {
302 NS_LOG_DEBUG("Sending a single MPDU, no previous frame to ack: request Normal Ack");
303 WifiNormalAck* acknowledgment = new WifiNormalAck;
304 acknowledgment->ackTxVector =
306 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::NORMAL_ACK);
307 return std::unique_ptr<WifiAcknowledgment>(acknowledgment);
308 }
309
310 // we get here if multiple MPDUs are being/have been sent
311 if (!hdr.IsBlockAckReq() && (txParams.GetSize(receiver) == 0 || m_useExplicitBar))
312 {
313 // in case of single MPDU, there are previous unacknowledged frames, thus
314 // we cannot use Implicit Block Ack Request policy, otherwise we get a
315 // normal ack as response
316 NS_LOG_DEBUG("Request to schedule a Block Ack Request");
317
318 WifiBarBlockAck* acknowledgment = new WifiBarBlockAck;
319 acknowledgment->blockAckReqTxVector =
321 acknowledgment->blockAckTxVector = acknowledgment->blockAckReqTxVector;
322 acknowledgment->barType = m_mac->GetQosTxop(tid)->GetBlockAckReqType(receiver, tid);
323 acknowledgment->baType = m_mac->GetQosTxop(tid)->GetBlockAckType(receiver, tid);
324 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::BLOCK_ACK);
325 return std::unique_ptr<WifiAcknowledgment>(acknowledgment);
326 }
327
329 "A-MPDU using Implicit Block Ack Request policy or BlockAckReq, request Block Ack");
330 WifiBlockAck* acknowledgment = new WifiBlockAck;
331 acknowledgment->blockAckTxVector =
333 acknowledgment->baType = m_mac->GetQosTxop(tid)->GetBlockAckType(receiver, tid);
334 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::NORMAL_ACK);
335 return std::unique_ptr<WifiAcknowledgment>(acknowledgment);
336}
337
338std::unique_ptr<WifiAcknowledgment>
340{
341 NS_LOG_FUNCTION(this << *msdu << &txParams);
342
343 // Aggregating an MSDU does not change the acknowledgment method
344 return nullptr;
345}
346
347std::unique_ptr<WifiAcknowledgment>
349 const WifiTxParameters& txParams)
350{
351 NS_LOG_FUNCTION(this << *mpdu << &txParams);
352 NS_ASSERT(txParams.m_txVector.IsDlMu());
354
355 const WifiMacHeader& hdr = mpdu->GetHeader();
356 Mac48Address receiver = hdr.GetAddr1();
357
358 const WifiTxParameters::PsduInfo* psduInfo = txParams.GetPsduInfo(receiver);
359
361 "QoS data frames only can be aggregated when transmitting a "
362 "DL MU PPDU acknowledged via a sequence of BAR and BA frames");
363 uint8_t tid = hdr.GetQosTid();
364 Ptr<QosTxop> edca = m_mac->GetQosTxop(QosUtilsMapTidToAc(tid));
365
366 NS_ASSERT(!txParams.m_acknowledgment ||
368
369 WifiDlMuBarBaSequence* acknowledgment = nullptr;
370 if (txParams.m_acknowledgment)
371 {
372 acknowledgment = static_cast<WifiDlMuBarBaSequence*>(txParams.m_acknowledgment.get());
373 }
374
375 if (psduInfo)
376 {
377 // an MPDU addressed to the same receiver has been already added
378 NS_ASSERT(acknowledgment);
379
380 if ((acknowledgment->stationsSendBlockAckReqTo.find(receiver) !=
381 acknowledgment->stationsSendBlockAckReqTo.end()) ||
382 (acknowledgment->stationsReplyingWithBlockAck.find(receiver) !=
383 acknowledgment->stationsReplyingWithBlockAck.end()))
384 {
385 // the receiver either is already listed among the stations that will
386 // receive a BlockAckReq frame or is the station that will immediately
387 // respond with a BlockAck frame, hence no change is needed
388 return nullptr;
389 }
390
391 // the receiver was scheduled for responding immediately with a Normal Ack.
392 // Given that we are adding an MPDU, the receiver must be scheduled for
393 // responding immediately with a Block Ack
394 NS_ASSERT(acknowledgment->stationsReplyingWithNormalAck.size() == 1 &&
395 acknowledgment->stationsReplyingWithNormalAck.begin()->first == receiver);
396
397 // acknowledgment points to the m_acknowledgment member of txParams, which is
398 // passed as const reference because it must not be modified. Therefore, we
399 // make a copy of the object pointed to by acknowledgment and make changes to
400 // the copy
401 acknowledgment = new WifiDlMuBarBaSequence(*acknowledgment);
402 acknowledgment->stationsReplyingWithNormalAck.clear();
403
404 acknowledgment->stationsReplyingWithBlockAck.emplace(
405 receiver,
408 edca->GetBlockAckType(receiver, tid)});
409 return std::unique_ptr<WifiDlMuBarBaSequence>(acknowledgment);
410 }
411
412 // we get here if this is the first MPDU for this receiver
413 if (edca->GetBaManager()->GetBar(true, tid, receiver) ||
414 (acknowledgment && (!acknowledgment->stationsReplyingWithNormalAck.empty() ||
415 !acknowledgment->stationsReplyingWithBlockAck.empty())))
416 {
417 // there is a pending BlockAckReq for this receiver or another receiver
418 // was selected for immediate response.
419 // Add this receiver to the list of stations receiving a BlockAckReq.
420 if (acknowledgment)
421 {
422 // txParams.m_acknowledgment points to an existing WifiDlMuBarBaSequence object.
423 // We have to return a copy of this object including the needed changes
424 acknowledgment = new WifiDlMuBarBaSequence(*acknowledgment);
425 }
426 else
427 {
428 // we have to create a new WifiDlMuBarBaSequence object
429 acknowledgment = new WifiDlMuBarBaSequence;
430 }
431
432 NS_LOG_DEBUG("Adding STA " << receiver
433 << " to the list of stations receiving a BlockAckReq");
434 acknowledgment->stationsSendBlockAckReqTo.emplace(
435 receiver,
438 edca->GetBlockAckReqType(receiver, tid),
440 edca->GetBlockAckType(receiver, tid)});
441
442 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::BLOCK_ACK);
443 return std::unique_ptr<WifiDlMuBarBaSequence>(acknowledgment);
444 }
445
446 // Add the receiver as the station that will immediately reply with a Normal Ack
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 << " as the station that will immediately reply with a Normal Ack");
461 acknowledgment->stationsReplyingWithNormalAck.emplace(
462 receiver,
465
466 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::NORMAL_ACK);
467 return std::unique_ptr<WifiDlMuBarBaSequence>(acknowledgment);
468}
469
470std::unique_ptr<WifiAcknowledgment>
472 const WifiTxParameters& txParams)
473{
474 NS_LOG_FUNCTION(this << *mpdu << &txParams);
475 NS_ASSERT(txParams.m_txVector.IsDlMu());
477
478 const WifiMacHeader& hdr = mpdu->GetHeader();
479 Mac48Address receiver = hdr.GetAddr1();
480
481 const WifiTxParameters::PsduInfo* psduInfo = txParams.GetPsduInfo(receiver);
482
483 NS_ASSERT(!txParams.m_acknowledgment ||
485
486 WifiDlMuTfMuBar* acknowledgment = nullptr;
487 if (txParams.m_acknowledgment)
488 {
489 acknowledgment = static_cast<WifiDlMuTfMuBar*>(txParams.m_acknowledgment.get());
490 }
491
492 if (!psduInfo)
493 {
494 // we get here if this is the first MPDU for this receiver.
495 Ptr<ApWifiMac> apMac = DynamicCast<ApWifiMac>(m_mac);
496 NS_ABORT_MSG_IF(!apMac, "HE APs only can send DL MU PPDUs");
497 uint16_t staId = apMac->GetAssociationId(receiver, m_linkId);
498
500 "QoS data frames only can be aggregated when transmitting a "
501 "DL MU PPDU acknowledged via a MU-BAR sent as SU frame");
502 uint8_t tid = hdr.GetQosTid();
503
504 // Add the receiver to the list of stations that will reply with a Block Ack
505 if (acknowledgment)
506 {
507 // txParams.m_acknowledgment points to an existing WifiDlMuTfMuBar object.
508 // We have to return a copy of this object including the needed changes
509 acknowledgment = new WifiDlMuTfMuBar(*acknowledgment);
510 }
511 else
512 {
513 // we have to create a new WifiDlMuTfMuBar object
514 acknowledgment = new WifiDlMuTfMuBar;
515 }
516
517 // determine the TX vector used to send the BlockAck frame
518 WifiTxVector blockAckTxVector;
520 blockAckTxVector.SetChannelWidth(txParams.m_txVector.GetChannelWidth());
521 blockAckTxVector.SetGuardInterval(txParams.m_txVector.GetGuardInterval());
522 const auto& userInfo = txParams.m_txVector.GetHeMuUserInfo(staId);
523 blockAckTxVector.SetHeMuUserInfo(
524 staId,
525 {userInfo.ru,
526 HePhy::GetHeMcs(std::min(userInfo.mcs.GetMcsValue(), m_maxMcsForBlockAckInTbPpdu)),
527 userInfo.nss});
528
529 NS_LOG_DEBUG("Adding STA "
530 << receiver
531 << " to the list of stations that will be solicited by the MU-BAR");
532 Ptr<QosTxop> edca = m_mac->GetQosTxop(QosUtilsMapTidToAc(tid));
533 acknowledgment->stationsReplyingWithBlockAck.emplace(
534 receiver,
535 WifiDlMuTfMuBar::BlockAckInfo{edca->GetBaManager()->GetBlockAckReqHeader(receiver, tid),
536 blockAckTxVector,
537 edca->GetBlockAckType(receiver, tid)});
538
539 acknowledgment->barTypes.push_back(edca->GetBlockAckReqType(receiver, tid));
540 acknowledgment->muBarTxVector = GetWifiRemoteStationManager()->GetRtsTxVector(receiver);
541 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::BLOCK_ACK);
542 return std::unique_ptr<WifiDlMuTfMuBar>(acknowledgment);
543 }
544
545 // an MPDU addressed to the same receiver has been already added
546 NS_ASSERT(acknowledgment);
548 "QoS data frames only can be aggregated when transmitting a DL MU PPDU");
549
550 // no change is needed
551 return nullptr;
552}
553
554std::unique_ptr<WifiAcknowledgment>
556 const WifiTxParameters& txParams)
557{
558 NS_LOG_FUNCTION(this << *mpdu << &txParams);
559 NS_ASSERT(txParams.m_txVector.IsDlMu());
561
562 const WifiMacHeader& hdr = mpdu->GetHeader();
563 Mac48Address receiver = hdr.GetAddr1();
564
565 const WifiTxParameters::PsduInfo* psduInfo = txParams.GetPsduInfo(receiver);
566
567 NS_ASSERT(!txParams.m_acknowledgment ||
569
570 WifiDlMuAggregateTf* acknowledgment = nullptr;
571 if (txParams.m_acknowledgment)
572 {
573 acknowledgment = static_cast<WifiDlMuAggregateTf*>(txParams.m_acknowledgment.get());
574 }
575
576 if (!psduInfo)
577 {
578 // we get here if this is the first MPDU for this receiver.
579 Ptr<ApWifiMac> apMac = DynamicCast<ApWifiMac>(m_mac);
580 NS_ABORT_MSG_IF(!apMac, "HE APs only can send DL MU PPDUs");
581 uint16_t staId = apMac->GetAssociationId(receiver, m_linkId);
582
584 "QoS data frames only can be aggregated when transmitting a "
585 "DL MU PPDU acknowledged via a sequence of BAR and BA frames");
586 uint8_t tid = hdr.GetQosTid();
587
588 // Add the receiver to the list of stations that will reply with a Block Ack
589 if (acknowledgment)
590 {
591 // txParams.m_acknowledgment points to an existing WifiDlMuAggregateTf object.
592 // We have to return a copy of this object including the needed changes
593 acknowledgment = new WifiDlMuAggregateTf(*acknowledgment);
594 }
595 else
596 {
597 // we have to create a new WifiDlMuAggregateTf object
598 acknowledgment = new WifiDlMuAggregateTf;
599 }
600
601 // determine the TX vector used to send the BlockAck frame
602 WifiTxVector blockAckTxVector;
604 blockAckTxVector.SetChannelWidth(txParams.m_txVector.GetChannelWidth());
605 blockAckTxVector.SetGuardInterval(txParams.m_txVector.GetGuardInterval());
606 const auto& userInfo = txParams.m_txVector.GetHeMuUserInfo(staId);
607 blockAckTxVector.SetHeMuUserInfo(
608 staId,
609 {userInfo.ru,
610 HePhy::GetHeMcs(std::min(userInfo.mcs.GetMcsValue(), m_maxMcsForBlockAckInTbPpdu)),
611 userInfo.nss});
612
613 NS_LOG_DEBUG("Adding STA " << receiver
614 << " to the list of stations that will reply with a Block Ack");
615 Ptr<QosTxop> edca = m_mac->GetQosTxop(QosUtilsMapTidToAc(tid));
616 acknowledgment->stationsReplyingWithBlockAck.emplace(
617 receiver,
619 GetMuBarSize({edca->GetBlockAckReqType(receiver, tid)}),
620 edca->GetBaManager()->GetBlockAckReqHeader(receiver, tid),
621 blockAckTxVector,
622 edca->GetBlockAckType(receiver, tid)});
623
624 acknowledgment->SetQosAckPolicy(receiver, tid, WifiMacHeader::NO_EXPLICIT_ACK);
625 return std::unique_ptr<WifiDlMuAggregateTf>(acknowledgment);
626 }
627
628 // an MPDU addressed to the same receiver has been already added
629 NS_ASSERT(acknowledgment);
631 !hdr.IsQosData(),
632 "QoS data and MU-BAR Trigger frames only can be aggregated when transmitting a DL MU PPDU");
633
634 // no change is needed
635 return nullptr;
636}
637
638std::unique_ptr<WifiAcknowledgment>
640 const WifiTxParameters& txParams)
641{
642 NS_LOG_FUNCTION(this << *mpdu << &txParams);
643 NS_ASSERT(mpdu->GetHeader().IsTrigger());
644
645 Ptr<ApWifiMac> apMac = DynamicCast<ApWifiMac>(m_mac);
646 NS_ABORT_MSG_IF(!apMac, "HE APs only can send Trigger Frames");
647
648 auto heFem = DynamicCast<HeFrameExchangeManager>(m_mac->GetFrameExchangeManager(m_linkId));
649 NS_ABORT_MSG_IF(!heFem, "HE APs only can send Trigger Frames");
650
651 CtrlTriggerHeader trigger;
652 mpdu->GetPacket()->PeekHeader(trigger);
653
654 if (trigger.IsBasic())
655 {
656 // the only supported ack method for now is through a multi-STA BlockAck frame
657 WifiUlMuMultiStaBa* acknowledgment = new WifiUlMuMultiStaBa;
658
659 for (const auto& userInfo : trigger)
660 {
661 uint16_t aid12 = userInfo.GetAid12();
662
663 if (aid12 == 2046)
664 {
665 NS_LOG_INFO("Unallocated RU");
666 continue;
667 }
668 NS_ABORT_MSG_IF(aid12 == 0 || aid12 > 2007, "Allocation of RA-RUs is not supported");
669
670 NS_ASSERT(apMac->GetStaList().find(aid12) != apMac->GetStaList().end());
671 Mac48Address staAddress = apMac->GetStaList().find(aid12)->second;
672
673 // find a TID for which a BA agreement exists with the given originator
674 uint8_t tid = 0;
675 while (tid < 8 && !heFem->GetBaAgreementEstablished(staAddress, tid))
676 {
677 tid++;
678 }
679 NS_ASSERT_MSG(tid < 8,
680 "No Block Ack agreement established with originator " << staAddress);
681
682 std::size_t index = acknowledgment->baType.m_bitmapLen.size();
683 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(staAddress, tid),
684 index);
685
686 // we assume the Block Acknowledgment context is used for the multi-STA BlockAck frame
687 // (since it requires the longest TX time due to the presence of a bitmap)
688 acknowledgment->baType.m_bitmapLen.push_back(
689 heFem->GetBlockAckType(staAddress, tid).m_bitmapLen.at(0));
690 }
691
692 uint16_t staId = trigger.begin()->GetAid12();
693 acknowledgment->tbPpduTxVector = trigger.GetHeTbTxVector(staId);
695 apMac->GetStaList().find(staId)->second,
696 acknowledgment->tbPpduTxVector);
697 return std::unique_ptr<WifiUlMuMultiStaBa>(acknowledgment);
698 }
699 else if (trigger.IsBsrp())
700 {
701 return std::unique_ptr<WifiAcknowledgment>(new WifiNoAck);
702 }
703
704 return nullptr;
705}
706
707} // namespace ns3
#define min(a, b)
Definition: 80211b.c:42
uint16_t GetAssociationId(Mac48Address addr, uint8_t linkId) const
const std::map< uint16_t, Mac48Address > & GetStaList(uint8_t linkId=SINGLE_LINK_OP_ID) const
Get a const reference to the map of associated stations on the given link.
AttributeValue implementation for Boolean.
Definition: boolean.h:37
Headers for Trigger frames.
Definition: ctrl-headers.h:886
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
static WifiMode GetHeMcs(uint8_t index)
Return the HE MCS corresponding to the provided index.
Definition: he-phy.cc:1444
an EUI-48 address
Definition: mac48-address.h:46
bool IsGroup() const
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:78
Ptr< BlockAckManager > GetBaManager()
Get the Block Ack Manager associated with this QosTxop.
Definition: qos-txop.cc:255
uint16_t GetBaBufferSize(Mac48Address address, uint8_t tid) const
Definition: qos-txop.cc:269
virtual Time GetRemainingTxop(uint8_t linkId) const
Return the remaining duration in the current TXOP on the given link.
Definition: qos-txop.cc:581
bool GetBaAgreementEstablished(Mac48Address address, uint8_t tid) const
Definition: qos-txop.cc:261
BlockAckType GetBlockAckType(Mac48Address recipient, uint8_t tid) const
Definition: qos-txop.cc:541
BlockAckReqType GetBlockAckReqType(Mac48Address recipient, uint8_t tid) const
Definition: qos-txop.cc:535
uint16_t GetBaStartingSequence(Mac48Address address, uint8_t tid) const
Definition: qos-txop.cc:275
bool IsStrictlyPositive() const
Exactly equivalent to t > 0.
Definition: nstime.h:350
Time GetTxopLimit() const
Return the TXOP limit.
Definition: txop.cc:473
Ptr< WifiMacQueue > GetWifiMacQueue() const
Return the packet queue associated with this Txop.
Definition: txop.cc:220
a unique identifier for an interface.
Definition: type-id.h:60
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:935
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...
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.
uint16_t GetSequenceNumber() const
Return the sequence number of the header.
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.
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.
HeMuUserInfo GetHeMuUserInfo(uint16_t staId) const
Get the HE MU user-specific transmission information for the given STA-ID.
bool IsDlMu() const
Return true if this TX vector is used for a downlink multi-user transmission.
bool IsUlMu() const
Return true if this TX vector is used for an uplink multi-user transmission.
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:45
AcIndex QosUtilsMapTidToAc(uint8_t tid)
Maps TID (Traffic ID) to Access classes.
Definition: qos-utils.cc:132
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:184
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:193
@ 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
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.
WifiAckAfterTbPpdu is used when a station prepares a TB PPDU to send in response to a Basic Trigger F...
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...
WifiBarBlockAck specifies that a BlockAckReq is sent to solicit a Block Ack response.
BlockAckType baType
BlockAck type.
WifiTxVector blockAckTxVector
BlockAck TXVECTOR.
WifiTxVector blockAckReqTxVector
BlockAckReq TXVECTOR.
BlockAckReqType barType
BlockAckReq type.
WifiBlockAck specifies that acknowledgment via Block Ack is required.
WifiTxVector blockAckTxVector
BlockAck TXVECTOR.
BlockAckType baType
BlockAck type.
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.
WifiNoAck specifies that no acknowledgment is required.
WifiNormalAck specifies that acknowledgment via Normal Ack is required.
WifiTxVector ackTxVector
Ack TXVECTOR.
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
WifiUlMuMultiStaBa specifies that a Basic Trigger Frame is being sent to solicit TB PPDUs that will b...
BlockAckType baType
BlockAck type.
WifiTxVector tbPpduTxVector
TXVECTOR for a TB PPDU.
WifiTxVector multiStaBaTxVector
TXVECTOR for the Multi-STA BlockAck.
std::map< std::pair< Mac48Address, uint8_t >, std::size_t > stationsReceivingMultiStaBa
Map (originator, tid) pairs to the their index in baType.