A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
ht-frame-exchange-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 "ns3/abort.h"
23#include "ns3/ctrl-headers.h"
24#include "ns3/log.h"
25#include "ns3/mgt-headers.h"
26#include "ns3/recipient-block-ack-agreement.h"
27#include "ns3/snr-tag.h"
28#include "ns3/wifi-mac-queue.h"
29#include "ns3/wifi-utils.h"
30
31#include <array>
32#include <optional>
33
34#undef NS_LOG_APPEND_CONTEXT
35#define NS_LOG_APPEND_CONTEXT std::clog << "[link=" << +m_linkId << "][mac=" << m_self << "] "
36
37namespace ns3
38{
39
40NS_LOG_COMPONENT_DEFINE("HtFrameExchangeManager");
41
42NS_OBJECT_ENSURE_REGISTERED(HtFrameExchangeManager);
43
44TypeId
46{
47 static TypeId tid = TypeId("ns3::HtFrameExchangeManager")
49 .AddConstructor<HtFrameExchangeManager>()
50 .SetGroupName("Wifi");
51 return tid;
52}
53
55{
56 NS_LOG_FUNCTION(this);
57 m_msduAggregator = CreateObject<MsduAggregator>();
58 m_mpduAggregator = CreateObject<MpduAggregator>();
59}
60
62{
64}
65
66void
68{
69 NS_LOG_FUNCTION(this);
70 m_pendingAddBaResp.clear();
71 m_msduAggregator = nullptr;
72 m_mpduAggregator = nullptr;
73 m_psdu = nullptr;
76}
77
78void
80{
81 m_msduAggregator->SetWifiMac(mac);
82 m_mpduAggregator->SetWifiMac(mac);
84}
85
88{
89 return m_msduAggregator;
90}
91
94{
95 return m_mpduAggregator;
96}
97
100{
101 return m_mac->GetQosTxop(tid)->GetBaManager();
102}
103
104bool
106{
107 Ptr<QosTxop> qosTxop = m_mac->GetQosTxop(tid);
108 bool establish;
109
110 if (!GetWifiRemoteStationManager()->GetHtSupported(recipient))
111 {
112 establish = false;
113 }
114 else if (auto agreement = qosTxop->GetBaManager()->GetAgreementAsOriginator(recipient, tid);
115 agreement && !agreement->get().IsReset())
116 {
117 establish = false;
118 }
119 else
120 {
121 WifiContainerQueueId queueId{WIFI_QOSDATA_UNICAST_QUEUE, recipient, tid};
122 uint32_t packets = qosTxop->GetWifiMacQueue()->GetNPackets(queueId);
123 establish =
124 ((qosTxop->GetBlockAckThreshold() > 0 && packets >= qosTxop->GetBlockAckThreshold()) ||
125 (m_mpduAggregator->GetMaxAmpduSize(recipient, tid, WIFI_MOD_CLASS_HT) > 0 &&
126 packets > 1) ||
128 }
129
130 NS_LOG_FUNCTION(this << recipient << +tid << establish);
131 return establish;
132}
133
134void
136 uint8_t tid,
137 uint16_t startingSeq,
138 uint16_t timeout,
139 bool immediateBAck)
140{
141 NS_LOG_FUNCTION(this << dest << +tid << startingSeq << timeout << immediateBAck);
142 NS_LOG_DEBUG("Send ADDBA request to " << dest);
143
144 WifiMacHeader hdr;
146 // use the remote link address if dest is an MLD address
148 hdr.SetAddr1(addr1 ? *addr1 : dest);
149 hdr.SetAddr2(m_self);
150 hdr.SetAddr3(m_bssid);
151 hdr.SetDsNotTo();
152 hdr.SetDsNotFrom();
153
154 WifiActionHeader actionHdr;
157 actionHdr.SetAction(WifiActionHeader::BLOCK_ACK, action);
158
159 Ptr<Packet> packet = Create<Packet>();
160 // Setting ADDBARequest header
162 reqHdr.SetAmsduSupport(true);
163 if (immediateBAck)
164 {
165 reqHdr.SetImmediateBlockAck();
166 }
167 else
168 {
169 reqHdr.SetDelayedBlockAck();
170 }
171 reqHdr.SetTid(tid);
172 /* For now we don't use buffer size field in the ADDBA request frame. The recipient
173 * will choose how many packets it can receive under block ack.
174 */
175 reqHdr.SetBufferSize(0);
176 reqHdr.SetTimeout(timeout);
177 // set the starting sequence number for the BA agreement
178 reqHdr.SetStartingSequence(startingSeq);
179
180 GetBaManager(tid)->CreateOriginatorAgreement(reqHdr, dest);
181
182 packet->AddHeader(reqHdr);
183 packet->AddHeader(actionHdr);
184
185 Ptr<WifiMpdu> mpdu = Create<WifiMpdu>(packet, hdr);
186
187 // get the sequence number for the ADDBA Request management frame
188 uint16_t sequence = m_txMiddle->GetNextSequenceNumberFor(&mpdu->GetHeader());
189 mpdu->GetHeader().SetSequenceNumber(sequence);
190
191 WifiTxParameters txParams;
192 txParams.m_txVector =
194 txParams.m_protection = std::unique_ptr<WifiProtection>(new WifiNoProtection);
195 txParams.m_acknowledgment = GetAckManager()->TryAddMpdu(mpdu, txParams);
196
197 // Wifi MAC queue scheduler is expected to prioritize management frames
198 m_mac->GetQosTxop(tid)->GetWifiMacQueue()->Enqueue(mpdu);
199 SendMpduWithProtection(mpdu, txParams);
200}
201
202void
204 Mac48Address originator)
205{
206 NS_LOG_FUNCTION(this << originator);
207 WifiMacHeader hdr;
209 hdr.SetAddr1(originator);
210 hdr.SetAddr2(m_self);
211 hdr.SetAddr3(m_bssid);
212 hdr.SetDsNotFrom();
213 hdr.SetDsNotTo();
214
216 StatusCode code;
217 code.SetSuccess();
218 respHdr.SetStatusCode(code);
219 // Here a control about queues type?
220 respHdr.SetAmsduSupport(reqHdr->IsAmsduSupported());
221
222 if (reqHdr->IsImmediateBlockAck())
223 {
224 respHdr.SetImmediateBlockAck();
225 }
226 else
227 {
228 respHdr.SetDelayedBlockAck();
229 }
230 auto tid = reqHdr->GetTid();
231 respHdr.SetTid(tid);
232
234 respHdr.SetTimeout(reqHdr->GetTimeout());
235
236 WifiActionHeader actionHdr;
239 actionHdr.SetAction(WifiActionHeader::BLOCK_ACK, action);
240
241 Ptr<Packet> packet = Create<Packet>();
242 packet->AddHeader(respHdr);
243 packet->AddHeader(actionHdr);
244
245 // Get the MLD address of the originator, if an ML setup was performed
246 if (auto originatorMld = GetWifiRemoteStationManager()->GetMldAddress(originator))
247 {
248 originator = *originatorMld;
249 }
250 bool htSupported = GetWifiRemoteStationManager()->GetHtSupported() &&
252 GetBaManager(tid)->CreateRecipientAgreement(respHdr,
253 originator,
254 reqHdr->GetStartingSequence(),
255 htSupported,
256 m_rxMiddle);
257
258 auto agreement = GetBaManager(tid)->GetAgreementAsRecipient(originator, tid);
259 NS_ASSERT(agreement);
260 if (respHdr.GetTimeout() != 0)
261 {
262 Time timeout = MicroSeconds(1024 * agreement->get().GetTimeout());
263
264 agreement->get().m_inactivityEvent =
267 this,
268 originator,
269 tid,
270 false);
271 }
272
273 auto mpdu = Create<WifiMpdu>(packet, hdr);
274
275 /*
276 * It is possible (though, unlikely) that at this point there are other ADDBA_RESPONSE frame(s)
277 * in the MAC queue. This may happen if the recipient receives an ADDBA_REQUEST frame, enqueues
278 * an ADDBA_RESPONSE frame, but is not able to successfully transmit it before the timer to
279 * wait for ADDBA_RESPONSE expires at the originator. The latter may then send another
280 * ADDBA_REQUEST frame, which triggers the creation of another ADDBA_RESPONSE frame.
281 * To avoid sending unnecessary ADDBA_RESPONSE frames, we keep track of the previously enqueued
282 * ADDBA_RESPONSE frame (if any), dequeue it and replace it with the new ADDBA_RESPONSE frame.
283 */
284
285 // remove any pending ADDBA_RESPONSE frame
286 AgreementKey key(originator, tid);
287 if (auto it = m_pendingAddBaResp.find(key); it != m_pendingAddBaResp.end())
288 {
289 NS_ASSERT_MSG(it->second, "The pointer to the pending ADDBA_RESPONSE cannot be null");
290 DequeueMpdu(it->second);
291 m_pendingAddBaResp.erase(it);
292 }
293 // store the new ADDBA_RESPONSE frame
294 m_pendingAddBaResp[key] = mpdu;
295
296 // It is unclear which queue this frame should go into. For now we
297 // bung it into the queue corresponding to the TID for which we are
298 // establishing an agreement, and push it to the head.
299 // Wifi MAC queue scheduler is expected to prioritize management frames
300 m_mac->GetQosTxop(tid)->Queue(mpdu);
301}
302
303uint16_t
305{
306 return 64;
307}
308
309void
310HtFrameExchangeManager::SendDelbaFrame(Mac48Address addr, uint8_t tid, bool byOriginator)
311{
312 NS_LOG_FUNCTION(this << addr << +tid << byOriginator);
313 WifiMacHeader hdr;
315 // use the remote link address if addr is an MLD address
316 hdr.SetAddr1(GetWifiRemoteStationManager()->GetAffiliatedStaAddress(addr).value_or(addr));
317 hdr.SetAddr2(m_self);
318 hdr.SetAddr3(m_bssid);
319 hdr.SetDsNotTo();
320 hdr.SetDsNotFrom();
321
322 MgtDelBaHeader delbaHdr;
323 delbaHdr.SetTid(tid);
324 if (byOriginator)
325 {
326 delbaHdr.SetByOriginator();
327 GetBaManager(tid)->DestroyOriginatorAgreement(addr, tid);
328 }
329 else
330 {
331 delbaHdr.SetByRecipient();
332 GetBaManager(tid)->DestroyRecipientAgreement(addr, tid);
333 }
334
335 WifiActionHeader actionHdr;
337 action.blockAck = WifiActionHeader::BLOCK_ACK_DELBA;
338 actionHdr.SetAction(WifiActionHeader::BLOCK_ACK, action);
339
340 Ptr<Packet> packet = Create<Packet>();
341 packet->AddHeader(delbaHdr);
342 packet->AddHeader(actionHdr);
343
344 m_mac->GetQosTxop(tid)->GetWifiMacQueue()->Enqueue(Create<WifiMpdu>(packet, hdr));
345}
346
347bool
348HtFrameExchangeManager::StartFrameExchange(Ptr<QosTxop> edca, Time availableTime, bool initialFrame)
349{
350 NS_LOG_FUNCTION(this << edca << availableTime << initialFrame);
351
352 // First, check if there is a BAR to be transmitted
353 if (auto mpdu = GetBar(edca->GetAccessCategory());
354 mpdu && SendMpduFromBaManager(mpdu, availableTime, initialFrame))
355 {
356 return true;
357 }
358
359 Ptr<WifiMpdu> peekedItem = edca->PeekNextMpdu(m_linkId);
360
361 // Even though channel access is requested when the queue is not empty, at
362 // the time channel access is granted the lifetime of the packet might be
363 // expired and the queue might be empty.
364 if (!peekedItem)
365 {
366 NS_LOG_DEBUG("No frames available for transmission");
367 return false;
368 }
369
370 const WifiMacHeader& hdr = peekedItem->GetHeader();
371 // setup a Block Ack agreement if needed
372 if (hdr.IsQosData() && !hdr.GetAddr1().IsGroup() &&
374 {
375 // if the peeked MPDU has been already transmitted, use its sequence number
376 // as the starting sequence number for the BA agreement, otherwise use the
377 // next available sequence number
378 uint16_t startingSeq =
379 (hdr.IsRetry()
380 ? hdr.GetSequenceNumber()
381 : m_txMiddle->GetNextSeqNumberByTidAndAddress(hdr.GetQosTid(), hdr.GetAddr1()));
383 hdr.GetQosTid(),
384 startingSeq,
385 edca->GetBlockAckInactivityTimeout(),
386 true);
387 return true;
388 }
389
390 // Use SendDataFrame if we can try aggregation
391 if (hdr.IsQosData() && !hdr.GetAddr1().IsGroup() && !peekedItem->IsFragment() &&
392 !GetWifiRemoteStationManager()->NeedFragmentation(peekedItem =
393 CreateAliasIfNeeded(peekedItem)))
394 {
395 return SendDataFrame(peekedItem, availableTime, initialFrame);
396 }
397
398 // Use the QoS FEM to transmit the frame in all the other cases, i.e.:
399 // - the frame is not a QoS data frame
400 // - the frame is a broadcast QoS data frame
401 // - the frame is a fragment
402 // - the frame must be fragmented
403 return QosFrameExchangeManager::StartFrameExchange(edca, availableTime, initialFrame);
404}
405
408 std::optional<uint8_t> optTid,
409 std::optional<Mac48Address> optAddress)
410{
411 NS_LOG_FUNCTION(this << +ac << optTid.has_value() << optAddress.has_value());
412 NS_ASSERT_MSG(optTid.has_value() == optAddress.has_value(),
413 "Either both or none of TID and address must be provided");
414
415 // remove all expired MPDUs from the MAC queue, so that
416 // BlockAckRequest frames (if needed) are scheduled
417 auto queue = m_mac->GetTxopQueue(ac);
418 queue->WipeAllExpiredMpdus();
419
420 // in case of MLD, we need to check both the queue of control frames that need to be sent
421 // on our link and the queue of control frames that can be sent on any link. We start with
422 // the former, but we check the latter even if a suitable frame is found in the former
423 // (because a BAR that can be sent on any link to a recipient is no longer needed after
424 // sending a BAR to that recipient on our link).
425
426 std::list<WifiContainerQueueId> queueIds{{WIFI_CTL_QUEUE, m_self, std::nullopt}};
427 if (m_self != m_mac->GetAddress())
428 {
429 // add the MLD address
430 queueIds.emplace_back(WIFI_CTL_QUEUE, m_mac->GetAddress(), std::nullopt);
431 }
432 Ptr<WifiMpdu> selectedBar;
433 uint8_t selectedTid = 0;
434
435 for (const auto& queueId : queueIds)
436 {
437 Ptr<WifiMpdu> bar;
438 Ptr<WifiMpdu> prevBar;
439
440 while ((bar = queue->PeekByQueueId(queueId, prevBar)))
441 {
442 if (bar->GetHeader().IsBlockAckReq())
443 {
445 bar->GetPacket()->PeekHeader(reqHdr);
446 auto tid = reqHdr.GetTidInfo();
447 Mac48Address recipient = bar->GetHeader().GetAddr1();
448
449 if (selectedBar)
450 {
451 NS_ASSERT_MSG(std::get<Mac48Address>(queueId) != m_self,
452 "We shall not keep iterating over the control frames that need"
453 "to be sent on a specific link after selecting a BAR to send");
454 // if this BlockAckReq is addressed to the same recipient as the selected BAR,
455 // remove it from the queue and stop iterating over this queue; otherwise,
456 // move on to the next frame in the queue
457 if (GetWifiRemoteStationManager()->GetAffiliatedStaAddress(recipient) ==
458 selectedBar->GetHeader().GetAddr1() &&
459 selectedTid == tid)
460 {
461 queue->Remove(bar);
462 break;
463 }
464 prevBar = bar;
465 continue;
466 }
467
468 // if this BlockAckReq can be sent on any link, we have to check that this link
469 // has been setup with the recipient (this may happen, e.g., if we are an AP MLD
470 // and we have setup a subset of our links with a non-AP MLD)
471 if (bar->GetHeader().GetAddr2() != m_self && m_mac->GetMldAddress(recipient) &&
472 !GetWifiRemoteStationManager()->GetAffiliatedStaAddress(recipient))
473 {
474 prevBar = bar;
475 continue;
476 }
477
478 if (optAddress &&
480 ->GetMldAddress(*optAddress)
481 .value_or(*optAddress) !=
482 GetWifiRemoteStationManager()->GetMldAddress(recipient).value_or(
483 recipient) ||
484 optTid != tid))
485 {
486 NS_LOG_DEBUG("BAR " << *bar
487 << " cannot be returned because it is not addressed"
488 " to the given station for the given TID");
489 prevBar = bar;
490 continue;
491 }
492
493 auto agreement = m_mac->GetBaAgreementEstablishedAsOriginator(recipient, tid);
494 if (!agreement)
495 {
496 NS_LOG_DEBUG("BA agreement with " << recipient << " for TID=" << +tid
497 << " was torn down");
498 queue->Remove(bar);
499 continue;
500 }
501 // update BAR if the starting sequence number changed
502 if (auto seqNo = agreement->get().GetStartingSequence();
503 reqHdr.GetStartingSequence() != seqNo)
504 {
505 reqHdr.SetStartingSequence(seqNo);
506 Ptr<Packet> packet = Create<Packet>();
507 packet->AddHeader(reqHdr);
508 auto updatedBar = Create<WifiMpdu>(packet, bar->GetHeader());
509 queue->Replace(bar, updatedBar);
510 bar = updatedBar;
511 }
512 // bar is the BlockAckReq to send
513 selectedBar = bar;
514 selectedTid = tid;
515 break;
516 }
517 if (bar->GetHeader().IsTrigger() && !optAddress && !selectedBar)
518 {
519 return bar;
520 }
521 // not a BAR nor a Trigger Frame, continue
522 prevBar = bar;
523 }
524 }
525
526 if (!selectedBar)
527 {
528 // check if we can send a BAR to a recipient to which a BAR can only be sent if data queued
529 auto baManager = m_mac->GetQosTxop(ac)->GetBaManager();
530 for (const auto& [recipient, tid] : baManager->GetSendBarIfDataQueuedList())
531 {
532 if (queue->PeekByTidAndAddress(tid, recipient))
533 {
534 selectedBar = m_mac->GetQosTxop(ac)->PrepareBlockAckRequest(recipient, tid);
535 baManager->RemoveFromSendBarIfDataQueuedList(recipient, tid);
536 queue->Enqueue(selectedBar);
537 break;
538 }
539 }
540 }
541
542 if (selectedBar && selectedBar->GetHeader().GetAddr2() != m_self)
543 {
544 // the selected BAR has MLD addresses in Addr1/Addr2, replace them with link addresses
545 // and move to the appropriate container queue
546 NS_ASSERT(selectedBar->GetHeader().GetAddr2() == m_mac->GetAddress());
547 DequeueMpdu(selectedBar);
548 const auto currAddr1 = selectedBar->GetHeader().GetAddr1();
549 auto addr1 =
550 GetWifiRemoteStationManager()->GetAffiliatedStaAddress(currAddr1).value_or(currAddr1);
551 selectedBar->GetHeader().SetAddr1(addr1);
552 selectedBar->GetHeader().SetAddr2(m_self);
553 queue->Enqueue(selectedBar);
554 }
555
556 return selectedBar;
557}
558
559bool
561 Time availableTime,
562 bool initialFrame)
563{
564 NS_LOG_FUNCTION(this << *mpdu << availableTime << initialFrame);
565
566 // First, check if there is a BAR to be transmitted
567 if (!mpdu->GetHeader().IsBlockAckReq())
568 {
569 NS_LOG_DEBUG("Block Ack Manager returned no frame to send");
570 return false;
571 }
572
573 // Prepare the TX parameters. Note that the default ack manager expects the
574 // data TxVector in the m_txVector field to compute the BlockAck TxVector.
575 // The m_txVector field of the TX parameters is set to the BlockAckReq TxVector
576 // a few lines below.
577 WifiTxParameters txParams;
578 txParams.m_txVector =
580 txParams.m_protection = std::unique_ptr<WifiProtection>(new WifiNoProtection);
581 txParams.m_acknowledgment = GetAckManager()->TryAddMpdu(mpdu, txParams);
582
584
585 WifiBlockAck* blockAcknowledgment = static_cast<WifiBlockAck*>(txParams.m_acknowledgment.get());
586 CalculateAcknowledgmentTime(blockAcknowledgment);
587 // the BlockAckReq frame is sent using the same TXVECTOR as the BlockAck frame
588 txParams.m_txVector = blockAcknowledgment->blockAckTxVector;
589
590 Time barTxDuration = m_phy->CalculateTxDuration(mpdu->GetSize(),
591 blockAcknowledgment->blockAckTxVector,
592 m_phy->GetPhyBand());
593
594 // if the available time is limited and we are not transmitting the initial
595 // frame of the TXOP, we have to check that this frame and its response fit
596 // within the given time limits
597 if (availableTime != Time::Min() && !initialFrame &&
598 barTxDuration + m_phy->GetSifs() + blockAcknowledgment->acknowledgmentTime > availableTime)
599 {
600 NS_LOG_DEBUG("Not enough time to send the BAR frame returned by the Block Ack Manager");
601 return false;
602 }
603
604 // we can transmit the BlockAckReq frame
605 SendPsduWithProtection(GetWifiPsdu(mpdu, txParams.m_txVector), txParams);
606 return true;
607}
608
609bool
611 Time availableTime,
612 bool initialFrame)
613{
614 NS_ASSERT(peekedItem && peekedItem->GetHeader().IsQosData() &&
615 !peekedItem->GetHeader().GetAddr1().IsBroadcast() && !peekedItem->IsFragment());
616 NS_LOG_FUNCTION(this << *peekedItem << availableTime << initialFrame);
617
618 Ptr<QosTxop> edca = m_mac->GetQosTxop(peekedItem->GetHeader().GetQosTid());
619 WifiTxParameters txParams;
620 txParams.m_txVector =
622 Ptr<WifiMpdu> mpdu =
623 edca->GetNextMpdu(m_linkId, peekedItem, txParams, availableTime, initialFrame);
624
625 if (!mpdu)
626 {
627 NS_LOG_DEBUG("Not enough time to transmit a frame");
628 return false;
629 }
630
631 // try A-MPDU aggregation
632 std::vector<Ptr<WifiMpdu>> mpduList =
633 m_mpduAggregator->GetNextAmpdu(mpdu, txParams, availableTime);
634 NS_ASSERT(txParams.m_acknowledgment);
635
636 if (mpduList.size() > 1)
637 {
638 // A-MPDU aggregation succeeded
639 SendPsduWithProtection(Create<WifiPsdu>(std::move(mpduList)), txParams);
640 }
641 else if (txParams.m_acknowledgment->method == WifiAcknowledgment::BAR_BLOCK_ACK)
642 {
643 // a QoS data frame using the Block Ack policy can be followed by a BlockAckReq
644 // frame and a BlockAck frame. Such a sequence is handled by the HT FEM
645 SendPsduWithProtection(Create<WifiPsdu>(mpdu, false), txParams);
646 }
647 else
648 {
649 // transmission can be handled by the base FEM
650 SendMpduWithProtection(mpdu, txParams);
651 }
652
653 return true;
654}
655
656void
658{
659 NS_LOG_FUNCTION(this << acknowledgment);
660 NS_ASSERT(acknowledgment);
661
662 if (acknowledgment->method == WifiAcknowledgment::BLOCK_ACK)
663 {
664 WifiBlockAck* blockAcknowledgment = static_cast<WifiBlockAck*>(acknowledgment);
665 Time baTxDuration = m_phy->CalculateTxDuration(GetBlockAckSize(blockAcknowledgment->baType),
666 blockAcknowledgment->blockAckTxVector,
667 m_phy->GetPhyBand());
668 blockAcknowledgment->acknowledgmentTime = m_phy->GetSifs() + baTxDuration;
669 }
670 else if (acknowledgment->method == WifiAcknowledgment::BAR_BLOCK_ACK)
671 {
672 WifiBarBlockAck* barBlockAcknowledgment = static_cast<WifiBarBlockAck*>(acknowledgment);
673 Time barTxDuration =
675 barBlockAcknowledgment->blockAckReqTxVector,
676 m_phy->GetPhyBand());
677 Time baTxDuration =
678 m_phy->CalculateTxDuration(GetBlockAckSize(barBlockAcknowledgment->baType),
679 barBlockAcknowledgment->blockAckTxVector,
680 m_phy->GetPhyBand());
681 barBlockAcknowledgment->acknowledgmentTime =
682 2 * m_phy->GetSifs() + barTxDuration + baTxDuration;
683 }
684 else
685 {
687 }
688}
689
690void
692{
693 ForwardPsduDown(GetWifiPsdu(mpdu, txVector), txVector);
694}
695
698{
699 return Create<WifiPsdu>(mpdu, false);
700}
701
702void
704{
705 NS_LOG_FUNCTION(this << *mpdu);
706
707 if (mpdu->GetHeader().IsQosData())
708 {
709 uint8_t tid = mpdu->GetHeader().GetQosTid();
710 Ptr<QosTxop> edca = m_mac->GetQosTxop(tid);
711
712 if (m_mac->GetBaAgreementEstablishedAsOriginator(mpdu->GetHeader().GetAddr1(), tid))
713 {
714 // notify the BA manager that the MPDU was acknowledged
715 edca->GetBaManager()->NotifyGotAck(m_linkId, mpdu);
716 }
717 }
718 else if (mpdu->GetHeader().IsAction())
719 {
720 auto addr1 = mpdu->GetHeader().GetAddr1();
721 auto address = GetWifiRemoteStationManager()->GetMldAddress(addr1).value_or(addr1);
722 WifiActionHeader actionHdr;
723 Ptr<Packet> p = mpdu->GetPacket()->Copy();
724 p->RemoveHeader(actionHdr);
725 if (actionHdr.GetCategory() == WifiActionHeader::BLOCK_ACK)
726 {
728 {
729 MgtDelBaHeader delBa;
730 p->PeekHeader(delBa);
731 auto tid = delBa.GetTid();
732 if (delBa.IsByOriginator())
733 {
734 GetBaManager(tid)->DestroyOriginatorAgreement(address, tid);
735 }
736 else
737 {
738 GetBaManager(tid)->DestroyRecipientAgreement(address, tid);
739 }
740 }
742 {
743 // Setup ADDBA response timeout
745 p->PeekHeader(addBa);
746 Ptr<QosTxop> edca = m_mac->GetQosTxop(addBa.GetTid());
747 Simulator::Schedule(edca->GetAddBaResponseTimeout(),
749 edca,
750 address,
751 addBa.GetTid());
752 }
754 {
755 // A recipient Block Ack agreement must exist
757 p->PeekHeader(addBa);
758 auto tid = addBa.GetTid();
759 NS_ASSERT_MSG(GetBaManager(tid)->GetAgreementAsRecipient(address, tid),
760 "Recipient BA agreement {" << address << ", " << +tid
761 << "} not found");
762 m_pendingAddBaResp.erase({address, tid});
763 }
764 }
765 }
767}
768
769void
771{
772 NS_LOG_DEBUG(this);
773
775 {
776 // A TXOP limit of 0 indicates that the TXOP holder may transmit or cause to
777 // be transmitted (as responses) the following within the current TXOP:
778 // f) Any number of BlockAckReq frames
779 // (Sec. 10.22.2.8 of 802.11-2016)
780 NS_LOG_DEBUG("Schedule a transmission from Block Ack Manager in a SIFS");
783
784 // TXOP limit is null, hence the txopDuration parameter is unused
786 }
787 else
788 {
790 }
791}
792
793void
795{
796 NS_LOG_FUNCTION(this << *mpdu);
797
798 if (mpdu->GetHeader().IsQosData())
799 {
800 GetBaManager(mpdu->GetHeader().GetQosTid())->NotifyDiscardedMpdu(mpdu);
801 }
802 else if (mpdu->GetHeader().IsAction())
803 {
804 WifiActionHeader actionHdr;
805 mpdu->GetPacket()->PeekHeader(actionHdr);
806 if (actionHdr.GetCategory() == WifiActionHeader::BLOCK_ACK &&
808 {
809 uint8_t tid = GetTid(mpdu->GetPacket(), mpdu->GetHeader());
810 auto recipient = mpdu->GetHeader().GetAddr1();
811 // if the recipient is an MLD, use its MLD address
812 if (auto mldAddr = GetWifiRemoteStationManager()->GetMldAddress(recipient))
813 {
814 recipient = *mldAddr;
815 }
816 if (auto agreement = GetBaManager(tid)->GetAgreementAsOriginator(recipient, tid);
817 agreement && agreement->get().IsPending())
818 {
819 NS_LOG_DEBUG("No ACK after ADDBA request");
820 Ptr<QosTxop> qosTxop = m_mac->GetQosTxop(tid);
821 qosTxop->NotifyOriginatorAgreementNoReply(recipient, tid);
822 Simulator::Schedule(qosTxop->GetFailedAddBaTimeout(),
824 qosTxop,
825 recipient,
826 tid);
827 }
828 }
829 }
831}
832
833void
835{
836 NS_LOG_FUNCTION(this << *mpdu);
837
838 if (mpdu->GetHeader().IsQosData())
839 {
840 uint8_t tid = mpdu->GetHeader().GetQosTid();
841 Ptr<QosTxop> edca = m_mac->GetQosTxop(tid);
842
843 if (m_mac->GetBaAgreementEstablishedAsOriginator(mpdu->GetHeader().GetAddr1(), tid))
844 {
845 // notify the BA manager that the MPDU was not acknowledged
846 edca->GetBaManager()->NotifyMissedAck(m_linkId, mpdu);
847 return;
848 }
849 }
851}
852
853void
855{
856 NS_LOG_FUNCTION(this << *psdu);
857
858 auto tids = psdu->GetTids();
859
860 if (tids.empty() || // no QoS data frames included
861 !m_mac->GetBaAgreementEstablishedAsOriginator(psdu->GetAddr1(), *tids.begin()))
862 {
864 return;
865 }
866
867 // iterate over MPDUs in reverse order (to process them in decreasing order of sequence number)
868 auto mpduIt = psdu->end();
869
870 do
871 {
872 std::advance(mpduIt, -1);
873
874 const WifiMacHeader& hdr = (*mpduIt)->GetOriginal()->GetHeader();
875 if (hdr.IsQosData())
876 {
877 uint8_t tid = hdr.GetQosTid();
879
880 if (!hdr.IsRetry() && !(*mpduIt)->IsInFlight())
881 {
882 // The MPDU has never been transmitted, so we can make its sequence
883 // number available again if it is the highest sequence number
884 // assigned by the MAC TX middle
885 uint16_t currentNextSeq = m_txMiddle->PeekNextSequenceNumberFor(&hdr);
886
887 if ((hdr.GetSequenceNumber() + 1) % SEQNO_SPACE_SIZE == currentNextSeq)
888 {
889 (*mpduIt)->UnassignSeqNo();
890 m_txMiddle->SetSequenceNumberFor(&hdr);
891
892 NS_LOG_DEBUG("Released " << hdr.GetSequenceNumber()
893 << ", next sequence "
894 "number for dest="
895 << hdr.GetAddr1() << ",tid=" << +tid << " is "
896 << m_txMiddle->PeekNextSequenceNumberFor(&hdr));
897 }
898 }
899 }
900 } while (mpduIt != psdu->begin());
901}
902
903Time
905{
906 NS_LOG_FUNCTION(this << txDuration << &txParams);
907
909
911 {
912 NS_ASSERT(txParams.m_acknowledgment &&
913 txParams.m_acknowledgment->acknowledgmentTime != Time::Min());
914 return txParams.m_acknowledgment->acknowledgmentTime;
915 }
916
917 // under multiple protection settings, if the TXOP limit is not null, Duration/ID
918 // is set to cover the remaining TXOP time (Sec. 9.2.5.2 of 802.11-2016).
919 // The TXOP holder may exceed the TXOP limit in some situations (Sec. 10.22.2.8
920 // of 802.11-2016)
921 return std::max(m_edca->GetRemainingTxop(m_linkId) - txDuration, Seconds(0));
922}
923
924void
926{
927 NS_LOG_FUNCTION(this << psdu << &txParams);
928
929 m_psdu = psdu;
930 m_txParams = std::move(txParams);
931
932#ifdef NS3_BUILD_PROFILE_DEBUG
933 // If protection is required, the MPDUs must be stored in some queue because
934 // they are not put back in a queue if the RTS/CTS exchange fails
936 {
937 for (const auto& mpdu : *PeekPointer(m_psdu))
938 {
939 NS_ASSERT(mpdu->GetHeader().IsCtl() || mpdu->IsQueued());
940 }
941 }
942#endif
943
944 // Make sure that the acknowledgment time has been computed, so that SendRts()
945 // and SendCtsToSelf() can reuse this value.
947
948 if (m_txParams.m_acknowledgment->acknowledgmentTime == Time::Min())
949 {
951 }
952
953 // Set QoS Ack policy
955
956 for (const auto& mpdu : *PeekPointer(m_psdu))
957 {
958 if (mpdu->IsQueued())
959 {
960 mpdu->SetInFlight(m_linkId);
961 }
962 }
963
965 {
967 }
969 {
971 }
972 else if (m_txParams.m_protection->method == WifiProtection::NONE)
973 {
974 SendPsdu();
975 }
976 else
977 {
978 NS_ABORT_MSG("Unknown protection type");
979 }
980}
981
982void
984{
985 NS_LOG_FUNCTION(this << *rts << txVector);
986
987 if (!m_psdu)
988 {
989 // A CTS Timeout occurred when protecting a single MPDU is handled by the
990 // parent classes
992 return;
993 }
994
996 m_psdu = nullptr;
997}
998
999void
1001{
1002 NS_LOG_FUNCTION(this);
1003
1004 Time txDuration =
1006
1008
1010 {
1012
1013 std::set<uint8_t> tids = m_psdu->GetTids();
1014 NS_ASSERT_MSG(tids.size() <= 1, "Multi-TID A-MPDUs are not supported");
1015
1016 if (tids.empty() || m_psdu->GetAckPolicyForTid(*tids.begin()) == WifiMacHeader::NO_ACK)
1017 {
1018 // No acknowledgment, hence dequeue the PSDU if it is stored in a queue
1020 }
1021 }
1023 {
1025
1026 // the timeout duration is "aSIFSTime + aSlotTime + aRxPHYStartDelay, starting
1027 // at the PHY-TXEND.confirm primitive" (section 10.3.2.9 or 10.22.2.2 of 802.11-2016).
1028 // aRxPHYStartDelay equals the time to transmit the PHY header.
1029 WifiBlockAck* blockAcknowledgment =
1030 static_cast<WifiBlockAck*>(m_txParams.m_acknowledgment.get());
1031
1032 Time timeout =
1033 txDuration + m_phy->GetSifs() + m_phy->GetSlot() +
1037 timeout,
1039 this,
1040 m_psdu,
1043 }
1045 {
1047
1048 // schedule the transmission of a BAR in a SIFS
1049 std::set<uint8_t> tids = m_psdu->GetTids();
1050 NS_ABORT_MSG_IF(tids.size() > 1,
1051 "Acknowledgment method incompatible with a Multi-TID A-MPDU");
1052 uint8_t tid = *tids.begin();
1053
1054 Ptr<QosTxop> edca = m_mac->GetQosTxop(tid);
1055 GetBaManager(tid)->ScheduleBar(edca->PrepareBlockAckRequest(m_psdu->GetAddr1(), tid));
1056
1058 }
1059 else
1060 {
1061 NS_ABORT_MSG("Unable to handle the selected acknowledgment method ("
1062 << m_txParams.m_acknowledgment.get() << ")");
1063 }
1064
1065 // transmit the PSDU
1066 if (m_psdu->GetNMpdus() > 1)
1067 {
1069 }
1070 else
1071 {
1073 }
1074
1076 {
1077 // we are done in case the A-MPDU does not require acknowledgment
1078 m_psdu = nullptr;
1079 }
1080}
1081
1082void
1084{
1085 NS_LOG_FUNCTION(this << psdu);
1086
1087 // use an array to avoid computing the queue size for every MPDU in the PSDU
1088 std::array<std::optional<uint8_t>, 8> queueSizeForTid;
1089
1090 for (const auto& mpdu : *PeekPointer(psdu))
1091 {
1092 WifiMacHeader& hdr = mpdu->GetHeader();
1093
1094 if (hdr.IsQosData())
1095 {
1096 uint8_t tid = hdr.GetQosTid();
1097 Ptr<QosTxop> edca = m_mac->GetQosTxop(tid);
1098
1099 if (m_mac->GetTypeOfStation() == STA && (m_setQosQueueSize || hdr.IsQosEosp()))
1100 {
1101 // set the Queue Size subfield of the QoS Control field
1102 if (!queueSizeForTid[tid].has_value())
1103 {
1104 queueSizeForTid[tid] = edca->GetQosQueueSize(tid, hdr.GetAddr1());
1105 }
1106
1107 hdr.SetQosEosp();
1108 hdr.SetQosQueueSize(queueSizeForTid[tid].value());
1109 }
1110
1111 if (hdr.HasData())
1112 {
1113 edca->CompleteMpduTx(mpdu);
1114 }
1115 }
1116 }
1117}
1118
1119void
1121{
1122 NS_LOG_DEBUG(this << psdu);
1123
1124 for (const auto& mpdu : *PeekPointer(psdu))
1125 {
1126 DequeueMpdu(mpdu);
1127 }
1128}
1129
1130void
1132{
1133 NS_LOG_FUNCTION(this << psdu << txVector);
1134
1135 NS_LOG_DEBUG("Transmitting a PSDU: " << *psdu << " TXVECTOR: " << txVector);
1136 NotifyTxToEdca(psdu);
1137
1138 if (psdu->IsAggregate())
1139 {
1140 txVector.SetAggregation(true);
1141 }
1142
1143 m_phy->Send(psdu, txVector);
1144}
1145
1146bool
1148 const WifiTxParameters& txParams,
1149 Time ppduDurationLimit) const
1150{
1151 NS_ASSERT(mpdu);
1152 NS_LOG_FUNCTION(this << *mpdu << &txParams << ppduDurationLimit);
1153
1154 Mac48Address receiver = mpdu->GetHeader().GetAddr1();
1155 uint32_t ampduSize = txParams.GetSizeIfAddMpdu(mpdu);
1156
1157 if (txParams.GetSize(receiver) > 0)
1158 {
1159 // we are attempting to perform A-MPDU aggregation, hence we have to check
1160 // that we meet the limit on the max A-MPDU size
1161 uint8_t tid;
1162 const WifiTxParameters::PsduInfo* info;
1163
1164 if (mpdu->GetHeader().IsQosData())
1165 {
1166 tid = mpdu->GetHeader().GetQosTid();
1167 }
1168 else if ((info = txParams.GetPsduInfo(receiver)) && !info->seqNumbers.empty())
1169 {
1170 tid = info->seqNumbers.begin()->first;
1171 }
1172 else
1173 {
1174 NS_ABORT_MSG("Cannot aggregate a non-QoS data frame to an A-MPDU that does"
1175 " not contain any QoS data frame");
1176 }
1177
1178 WifiModulationClass modulation = txParams.m_txVector.GetModulationClass();
1179
1180 if (!IsWithinAmpduSizeLimit(ampduSize, receiver, tid, modulation))
1181 {
1182 return false;
1183 }
1184 }
1185
1186 return IsWithinSizeAndTimeLimits(ampduSize, receiver, txParams, ppduDurationLimit);
1187}
1188
1189bool
1191 Mac48Address receiver,
1192 uint8_t tid,
1193 WifiModulationClass modulation) const
1194{
1195 NS_LOG_FUNCTION(this << ampduSize << receiver << +tid << modulation);
1196
1197 uint32_t maxAmpduSize = m_mpduAggregator->GetMaxAmpduSize(receiver, tid, modulation);
1198
1199 if (maxAmpduSize == 0)
1200 {
1201 NS_LOG_DEBUG("A-MPDU aggregation disabled");
1202 return false;
1203 }
1204
1205 if (ampduSize > maxAmpduSize)
1206 {
1207 NS_LOG_DEBUG("the frame does not meet the constraint on max A-MPDU size (" << maxAmpduSize
1208 << ")");
1209 return false;
1210 }
1211 return true;
1212}
1213
1214bool
1216 WifiTxParameters& txParams,
1217 Time availableTime) const
1218{
1219 NS_ASSERT(msdu && msdu->GetHeader().IsQosData());
1220 NS_LOG_FUNCTION(this << *msdu << &txParams << availableTime);
1221
1222 // check if aggregating the given MSDU requires a different protection method
1223 NS_ASSERT(txParams.m_protection);
1224 Time protectionTime = txParams.m_protection->protectionTime;
1225
1226 std::unique_ptr<WifiProtection> protection;
1227 protection = GetProtectionManager()->TryAggregateMsdu(msdu, txParams);
1228 bool protectionSwapped = false;
1229
1230 if (protection)
1231 {
1232 // the protection method has changed, calculate the new protection time
1233 CalculateProtectionTime(protection.get());
1234 protectionTime = protection->protectionTime;
1235 // swap unique pointers, so that the txParams that is passed to the next
1236 // call to IsWithinLimitsIfAggregateMsdu is the most updated one
1237 txParams.m_protection.swap(protection);
1238 protectionSwapped = true;
1239 }
1240 NS_ASSERT(protectionTime != Time::Min());
1241
1242 // check if aggregating the given MSDU requires a different acknowledgment method
1243 NS_ASSERT(txParams.m_acknowledgment);
1244 Time acknowledgmentTime = txParams.m_acknowledgment->acknowledgmentTime;
1245
1246 std::unique_ptr<WifiAcknowledgment> acknowledgment;
1247 acknowledgment = GetAckManager()->TryAggregateMsdu(msdu, txParams);
1248 bool acknowledgmentSwapped = false;
1249
1250 if (acknowledgment)
1251 {
1252 // the acknowledgment method has changed, calculate the new acknowledgment time
1253 CalculateAcknowledgmentTime(acknowledgment.get());
1254 acknowledgmentTime = acknowledgment->acknowledgmentTime;
1255 // swap unique pointers, so that the txParams that is passed to the next
1256 // call to IsWithinLimitsIfAggregateMsdu is the most updated one
1257 txParams.m_acknowledgment.swap(acknowledgment);
1258 acknowledgmentSwapped = true;
1259 }
1260 NS_ASSERT(acknowledgmentTime != Time::Min());
1261
1262 Time ppduDurationLimit = Time::Min();
1263 if (availableTime != Time::Min())
1264 {
1265 ppduDurationLimit = availableTime - protectionTime - acknowledgmentTime;
1266 }
1267
1268 if (!IsWithinLimitsIfAggregateMsdu(msdu, txParams, ppduDurationLimit))
1269 {
1270 // adding MPDU failed, restore protection and acknowledgment methods
1271 // if they were swapped
1272 if (protectionSwapped)
1273 {
1274 txParams.m_protection.swap(protection);
1275 }
1276 if (acknowledgmentSwapped)
1277 {
1278 txParams.m_acknowledgment.swap(acknowledgment);
1279 }
1280 return false;
1281 }
1282
1283 // the given MPDU can be added, hence update the txParams
1284 txParams.AggregateMsdu(msdu);
1285 UpdateTxDuration(msdu->GetHeader().GetAddr1(), txParams);
1286
1287 return true;
1288}
1289
1290bool
1292 const WifiTxParameters& txParams,
1293 Time ppduDurationLimit) const
1294{
1295 NS_ASSERT(msdu && msdu->GetHeader().IsQosData());
1296 NS_LOG_FUNCTION(this << *msdu << &txParams << ppduDurationLimit);
1297
1298 std::pair<uint16_t, uint32_t> ret = txParams.GetSizeIfAggregateMsdu(msdu);
1299 Mac48Address receiver = msdu->GetHeader().GetAddr1();
1300 uint8_t tid = msdu->GetHeader().GetQosTid();
1301 WifiModulationClass modulation = txParams.m_txVector.GetModulationClass();
1302
1303 // Check that the limit on A-MSDU size is met
1304 uint16_t maxAmsduSize = m_msduAggregator->GetMaxAmsduSize(receiver, tid, modulation);
1305
1306 if (maxAmsduSize == 0)
1307 {
1308 NS_LOG_DEBUG("A-MSDU aggregation disabled");
1309 return false;
1310 }
1311
1312 if (ret.first > maxAmsduSize)
1313 {
1314 NS_LOG_DEBUG("No other MSDU can be aggregated: maximum A-MSDU size (" << maxAmsduSize
1315 << ") reached ");
1316 return false;
1317 }
1318
1319 const WifiTxParameters::PsduInfo* info = txParams.GetPsduInfo(msdu->GetHeader().GetAddr1());
1320 NS_ASSERT(info);
1321
1322 if (info->ampduSize > 0)
1323 {
1324 // the A-MSDU being built is aggregated to other MPDUs in an A-MPDU.
1325 // Check that the limit on A-MPDU size is met.
1326 if (!IsWithinAmpduSizeLimit(ret.second, receiver, tid, modulation))
1327 {
1328 return false;
1329 }
1330 }
1331
1332 return IsWithinSizeAndTimeLimits(ret.second, receiver, txParams, ppduDurationLimit);
1333}
1334
1335void
1337{
1338 NS_LOG_FUNCTION(this << *psdu << txVector);
1339
1341
1342 bool resetCw;
1343 MissedBlockAck(psdu, txVector, resetCw);
1344
1346
1347 if (resetCw)
1348 {
1350 }
1351 else
1352 {
1354 }
1355
1356 m_psdu = nullptr;
1358}
1359
1360void
1362 const WifiTxVector& txVector,
1363 bool& resetCw)
1364{
1365 NS_LOG_FUNCTION(this << psdu << txVector << resetCw);
1366
1367 auto recipient = psdu->GetAddr1();
1368 auto recipientMld = GetWifiRemoteStationManager()->GetMldAddress(recipient).value_or(recipient);
1369 bool isBar;
1370 uint8_t tid;
1371
1372 if (psdu->GetNMpdus() == 1 && psdu->GetHeader(0).IsBlockAckReq())
1373 {
1374 isBar = true;
1375 CtrlBAckRequestHeader baReqHdr;
1376 psdu->GetPayload(0)->PeekHeader(baReqHdr);
1377 tid = baReqHdr.GetTidInfo();
1378 }
1379 else
1380 {
1381 isBar = false;
1383 ->ReportAmpduTxStatus(recipient, 0, psdu->GetNMpdus(), 0, 0, txVector);
1384 std::set<uint8_t> tids = psdu->GetTids();
1385 NS_ABORT_MSG_IF(tids.size() > 1, "Multi-TID A-MPDUs not handled here");
1386 NS_ASSERT(!tids.empty());
1387 tid = *tids.begin();
1388 }
1389
1390 Ptr<QosTxop> edca = m_mac->GetQosTxop(tid);
1391
1392 if (edca->UseExplicitBarAfterMissedBlockAck() || isBar)
1393 {
1394 // we have to send a BlockAckReq, if needed
1395 if (GetBaManager(tid)->NeedBarRetransmission(tid, recipientMld))
1396 {
1397 NS_LOG_DEBUG("Missed Block Ack, transmit a BlockAckReq");
1408 if (isBar)
1409 {
1410 psdu->GetHeader(0).SetRetry();
1411 }
1412 else
1413 {
1414 // missed block ack after data frame with Implicit BAR Ack policy
1415 GetBaManager(tid)->ScheduleBar(edca->PrepareBlockAckRequest(recipient, tid));
1416 }
1417 resetCw = false;
1418 }
1419 else
1420 {
1421 NS_LOG_DEBUG("Missed Block Ack, do not transmit a BlockAckReq");
1422 // if a BA agreement exists, we can get here if there is no outstanding
1423 // MPDU whose lifetime has not expired yet.
1425 if (isBar)
1426 {
1427 DequeuePsdu(psdu);
1428 }
1429 if (m_mac->GetBaAgreementEstablishedAsOriginator(recipient, tid))
1430 {
1431 // schedule a BlockAckRequest to be sent only if there are data frames queued
1432 // for this recipient
1433 GetBaManager(tid)->AddToSendBarIfDataQueuedList(recipientMld, tid);
1434 }
1435 resetCw = true;
1436 }
1437 }
1438 else
1439 {
1440 // we have to retransmit the data frames, if needed
1441 if (!GetWifiRemoteStationManager()->NeedRetransmission(*psdu->begin()))
1442 {
1443 NS_LOG_DEBUG("Missed Block Ack, do not retransmit the data frames");
1445 for (const auto& mpdu : *PeekPointer(psdu))
1446 {
1448 DequeueMpdu(mpdu);
1449 }
1450 resetCw = true;
1451 }
1452 else
1453 {
1454 NS_LOG_DEBUG("Missed Block Ack, retransmit data frames");
1455 GetBaManager(tid)->NotifyMissedBlockAck(m_linkId, recipientMld, tid);
1456 resetCw = false;
1457 }
1458 }
1459}
1460
1461void
1463 Time durationId,
1464 WifiTxVector& blockAckTxVector,
1465 double rxSnr)
1466{
1467 NS_LOG_FUNCTION(this << durationId << blockAckTxVector << rxSnr);
1468
1469 WifiMacHeader hdr;
1471 auto addr1 = agreement.GetPeer();
1472 if (auto originator = GetWifiRemoteStationManager()->GetAffiliatedStaAddress(addr1))
1473 {
1474 addr1 = *originator;
1475 }
1476 hdr.SetAddr1(addr1);
1477 hdr.SetAddr2(m_self);
1478 hdr.SetDsNotFrom();
1479 hdr.SetDsNotTo();
1480
1481 CtrlBAckResponseHeader blockAck;
1482 blockAck.SetType(agreement.GetBlockAckType());
1483 blockAck.SetTidInfo(agreement.GetTid());
1484 agreement.FillBlockAckBitmap(&blockAck);
1485
1486 Ptr<Packet> packet = Create<Packet>();
1487 packet->AddHeader(blockAck);
1488 Ptr<WifiPsdu> psdu = GetWifiPsdu(Create<WifiMpdu>(packet, hdr), blockAckTxVector);
1489
1490 // 802.11-2016, Section 9.2.5.7: In a BlockAck frame transmitted in response
1491 // to a BlockAckReq frame or transmitted in response to a frame containing an
1492 // implicit block ack request, the Duration/ID field is set to the value obtained
1493 // from the Duration/ ID field of the frame that elicited the response minus the
1494 // time, in microseconds between the end of the PPDU carrying the frame that
1495 // elicited the response and the end of the PPDU carrying the BlockAck frame.
1496 Time baDurationId = durationId - m_phy->GetSifs() -
1497 m_phy->CalculateTxDuration(psdu, blockAckTxVector, m_phy->GetPhyBand());
1498 // The TXOP holder may exceed the TXOP limit in some situations (Sec. 10.22.2.8 of 802.11-2016)
1499 if (baDurationId.IsStrictlyNegative())
1500 {
1501 baDurationId = Seconds(0);
1502 }
1503 psdu->GetHeader(0).SetDuration(baDurationId);
1504
1505 SnrTag tag;
1506 tag.Set(rxSnr);
1507 psdu->GetPayload(0)->AddPacketTag(tag);
1508
1509 ForwardPsduDown(psdu, blockAckTxVector);
1510}
1511
1512void
1514 RxSignalInfo rxSignalInfo,
1515 const WifiTxVector& txVector,
1516 bool inAmpdu)
1517{
1518 // The received MPDU is either broadcast or addressed to this station
1519 NS_ASSERT(mpdu->GetHeader().GetAddr1().IsGroup() || mpdu->GetHeader().GetAddr1() == m_self);
1520
1521 double rxSnr = rxSignalInfo.snr;
1522 const WifiMacHeader& hdr = mpdu->GetHeader();
1523
1524 if (hdr.IsCtl())
1525 {
1526 if (hdr.IsCts() && m_txTimer.IsRunning() &&
1528 {
1529 NS_ABORT_MSG_IF(inAmpdu, "Received CTS as part of an A-MPDU");
1530 NS_ASSERT(hdr.GetAddr1() == m_self);
1531
1532 Mac48Address sender = m_psdu->GetAddr1();
1533 NS_LOG_DEBUG("Received CTS from=" << sender);
1534
1535 SnrTag tag;
1536 mpdu->GetPacket()->PeekPacketTag(tag);
1537 GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
1539 rxSnr,
1540 txVector.GetMode(),
1541 tag.Get());
1542
1543 m_txTimer.Cancel();
1546 }
1547 else if (hdr.IsBlockAck() && m_txTimer.IsRunning() &&
1549 {
1550 Mac48Address sender = hdr.GetAddr2();
1551 NS_LOG_DEBUG("Received BlockAck from=" << sender);
1552
1553 SnrTag tag;
1554 mpdu->GetPacket()->PeekPacketTag(tag);
1555
1556 // notify the Block Ack Manager
1557 CtrlBAckResponseHeader blockAck;
1558 mpdu->GetPacket()->PeekHeader(blockAck);
1559 uint8_t tid = blockAck.GetTidInfo();
1560 std::pair<uint16_t, uint16_t> ret =
1561 GetBaManager(tid)->NotifyGotBlockAck(m_linkId,
1562 blockAck,
1563 m_mac->GetMldAddress(sender).value_or(sender),
1564 {tid});
1566 ret.first,
1567 ret.second,
1568 rxSnr,
1569 tag.Get(),
1571
1572 // cancel the timer
1573 m_txTimer.Cancel();
1575
1576 // Reset the CW
1578
1579 // if this BlockAck was sent in response to a BlockAckReq, dequeue the blockAckReq
1580 if (m_psdu && m_psdu->GetNMpdus() == 1 && m_psdu->GetHeader(0).IsBlockAckReq())
1581 {
1583 }
1584 m_psdu = nullptr;
1586 }
1587 else if (hdr.IsBlockAckReq())
1588 {
1589 NS_ASSERT(hdr.GetAddr1() == m_self);
1590 NS_ABORT_MSG_IF(inAmpdu, "BlockAckReq in A-MPDU is not supported");
1591
1592 Mac48Address sender = hdr.GetAddr2();
1593 NS_LOG_DEBUG("Received BlockAckReq from=" << sender);
1594
1595 CtrlBAckRequestHeader blockAckReq;
1596 mpdu->GetPacket()->PeekHeader(blockAckReq);
1597 NS_ABORT_MSG_IF(blockAckReq.IsMultiTid(), "Multi-TID BlockAckReq not supported");
1598 uint8_t tid = blockAckReq.GetTidInfo();
1599
1600 auto agreement = m_mac->GetBaAgreementEstablishedAsRecipient(sender, tid);
1601
1602 if (!agreement)
1603 {
1604 NS_LOG_DEBUG("There's not a valid agreement for this BlockAckReq");
1605 return;
1606 }
1607
1608 GetBaManager(tid)->NotifyGotBlockAckRequest(
1609 m_mac->GetMldAddress(sender).value_or(sender),
1610 tid,
1611 blockAckReq.GetStartingSequence());
1612
1613 NS_LOG_DEBUG("Schedule Block Ack");
1615 m_phy->GetSifs(),
1617 this,
1618 *agreement,
1619 hdr.GetDuration(),
1620 GetWifiRemoteStationManager()->GetBlockAckTxVector(sender, txVector),
1621 rxSnr);
1622 }
1623 else
1624 {
1625 // the received control frame cannot be handled here
1626 QosFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
1627 }
1628 return;
1629 }
1630
1631 if (hdr.IsQosData() && hdr.HasData() && hdr.GetAddr1() == m_self)
1632 {
1633 uint8_t tid = hdr.GetQosTid();
1634
1636 {
1637 // a Block Ack agreement has been established
1638 NS_LOG_DEBUG("Received from=" << hdr.GetAddr2() << " (" << *mpdu << ")");
1639
1640 GetBaManager(tid)->NotifyGotMpdu(mpdu);
1641
1642 if (!inAmpdu && hdr.GetQosAckPolicy() == WifiMacHeader::NORMAL_ACK)
1643 {
1644 NS_LOG_DEBUG("Schedule Normal Ack");
1647 this,
1648 hdr,
1649 txVector,
1650 rxSnr);
1651 }
1652 return;
1653 }
1654 // We let the QosFrameExchangeManager handle QoS data frame not belonging
1655 // to a Block Ack agreement
1656 }
1657
1658 QosFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
1659}
1660
1661void
1663 const RxSignalInfo& rxSignalInfo,
1664 const WifiTxVector& txVector,
1665 const std::vector<bool>& perMpduStatus)
1666{
1667 std::set<uint8_t> tids = psdu->GetTids();
1668
1669 // Multi-TID A-MPDUs are not supported yet
1670 if (tids.size() == 1)
1671 {
1672 uint8_t tid = *tids.begin();
1673 WifiMacHeader::QosAckPolicy ackPolicy = psdu->GetAckPolicyForTid(tid);
1674 NS_ASSERT(psdu->GetNMpdus() > 1);
1675
1676 if (ackPolicy == WifiMacHeader::NORMAL_ACK)
1677 {
1678 // Normal Ack or Implicit Block Ack Request
1679 NS_LOG_DEBUG("Schedule Block Ack");
1680 auto agreement = m_mac->GetBaAgreementEstablishedAsRecipient(psdu->GetAddr2(), tid);
1681 NS_ASSERT(agreement);
1682
1684 m_phy->GetSifs(),
1686 this,
1687 *agreement,
1688 psdu->GetDuration(),
1689 GetWifiRemoteStationManager()->GetBlockAckTxVector(psdu->GetAddr2(), txVector),
1690 rxSignalInfo.snr);
1691 }
1692 }
1693}
1694
1695} // namespace ns3
BlockAckType GetBlockAckType() const
Get the type of the Block Acks sent by the recipient of this agreement.
uint8_t GetTid() const
Return the Traffic ID (TID).
Mac48Address GetPeer() const
Return the peer address.
void NotifyAckTimeoutResetNow()
Notify that ack timer has reset.
void NotifyAckTimeoutStartNow(Time duration)
Notify that ack timer has started for the given duration.
void NotifyCtsTimeoutResetNow()
Notify that CTS timer has reset.
Headers for BlockAckRequest.
Definition: ctrl-headers.h:52
uint16_t GetStartingSequence() const
Return the starting sequence number.
uint8_t GetTidInfo() const
Return the Traffic ID (TID).
bool IsMultiTid() const
Check if the current Ack Policy has Multi-TID Block Ack.
void SetStartingSequence(uint16_t seq)
Set the starting sequence number from the given raw sequence control field.
Headers for BlockAck response.
Definition: ctrl-headers.h:203
uint8_t GetTidInfo(std::size_t index=0) const
For Block Ack variants other than Multi-STA Block Ack, get the TID_INFO subfield of the BA Control fi...
void SetTidInfo(uint8_t tid, std::size_t index=0)
For Block Ack variants other than Multi-STA Block Ack, set the TID_INFO subfield of the BA Control fi...
void SetType(BlockAckType type)
Set the block ack type.
void DoCtsTimeout(Ptr< WifiPsdu > psdu)
Take required actions when the CTS timer fired after sending an RTS to protect the given PSDU expires...
uint8_t m_linkId
the ID of the link this object is associated with
Ptr< WifiMac > m_mac
the MAC layer on this station
virtual void SetWifiMac(const Ptr< WifiMac > mac)
Set the MAC layer to use.
void SendMpduWithProtection(Ptr< WifiMpdu > mpdu, WifiTxParameters &txParams)
Send an MPDU with the given TX parameters (with the specified protection).
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager() const
void UpdateTxDuration(Mac48Address receiver, WifiTxParameters &txParams) const
Update the TX duration field of the given TX parameters after that the PSDU addressed to the given re...
virtual void CalculateAcknowledgmentTime(WifiAcknowledgment *acknowledgment) const
Calculate the time required to acknowledge a frame according to the given acknowledgment method.
Ptr< MacTxMiddle > m_txMiddle
the MAC TX Middle on this station
void SendNormalAck(const WifiMacHeader &hdr, const WifiTxVector &dataTxVector, double dataSnr)
Send Normal Ack.
Mac48Address m_self
the MAC address of this device
uint16_t m_allowedWidth
the allowed width in MHz for the current transmission
virtual void NotifyPacketDiscarded(Ptr< const WifiMpdu > mpdu)
Pass the given MPDU, discarded because of the max retry limit was reached, to the MPDU dropped callba...
WifiTxTimer m_txTimer
the timer set upon frame transmission
virtual void RetransmitMpduAfterMissedAck(Ptr< WifiMpdu > mpdu) const
Retransmit an MPDU that was not acknowledged.
void SendRts(const WifiTxParameters &txParams)
Send RTS to begin RTS-CTS-Data-Ack transaction.
virtual void NotifyReceivedNormalAck(Ptr< WifiMpdu > mpdu)
Notify other components that an MPDU was acknowledged.
void SendCtsToSelf(const WifiTxParameters &txParams)
Send CTS for a CTS-to-self mechanism.
virtual void CtsTimeout(Ptr< WifiMpdu > rts, const WifiTxVector &txVector)
Called when the CTS timeout expires.
virtual void CalculateProtectionTime(WifiProtection *protection) const
Calculate the time required to protect a frame according to the given protection method.
Ptr< WifiAckManager > GetAckManager() const
Get the Acknowledgment Manager used by this node.
virtual void DequeueMpdu(Ptr< const WifiMpdu > mpdu)
Dequeue the given MPDU from the queue in which it is stored.
Ptr< WifiProtectionManager > GetProtectionManager() const
Get the Protection Manager used by this node.
Ptr< MacRxMiddle > m_rxMiddle
the MAC RX Middle on this station
Ptr< WifiPhy > m_phy
the PHY layer on this station
virtual void ReleaseSequenceNumbers(Ptr< const WifiPsdu > psdu) const
Make the sequence numbers of MPDUs included in the given PSDU available again if the MPDUs have never...
Mac48Address m_bssid
BSSID address (Mac48Address)
Ptr< ChannelAccessManager > m_channelAccessManager
the channel access manager
virtual bool StartTransmission(Ptr< Txop > dcf, uint16_t allowedWidth)
Request the FrameExchangeManager to start a frame exchange sequence.
HtFrameExchangeManager handles the frame exchange sequences for HT stations.
Ptr< MpduAggregator > m_mpduAggregator
A-MPDU aggregator.
void ReceiveMpdu(Ptr< const WifiMpdu > mpdu, RxSignalInfo rxSignalInfo, const WifiTxVector &txVector, bool inAmpdu) override
This method handles the reception of an MPDU (possibly included in an A-MPDU)
void SendAddBaRequest(Mac48Address recipient, uint8_t tid, uint16_t startingSeq, uint16_t timeout, bool immediateBAck)
Sends an ADDBA Request to establish a block ack agreement with STA addressed by recipient for TID tid...
void SendDelbaFrame(Mac48Address addr, uint8_t tid, bool byOriginator)
Sends DELBA frame to cancel a block ack agreement with STA addressed by addr for TID tid.
std::map< AgreementKey, Ptr< WifiMpdu > > m_pendingAddBaResp
pending ADDBA_RESPONSE frames indexed by agreement key
void SendAddBaResponse(const MgtAddBaRequestHeader *reqHdr, Mac48Address originator)
This method can be called to accept a received ADDBA Request.
void CtsTimeout(Ptr< WifiMpdu > rts, const WifiTxVector &txVector) override
Called when the CTS timeout expires.
Ptr< WifiPsdu > m_psdu
the A-MPDU being transmitted
Ptr< BlockAckManager > GetBaManager(uint8_t tid) const
Get the Block Ack Manager handling the given TID.
virtual Ptr< WifiPsdu > GetWifiPsdu(Ptr< WifiMpdu > mpdu, const WifiTxVector &txVector) const
Get a PSDU containing the given MPDU.
virtual void BlockAckTimeout(Ptr< WifiPsdu > psdu, const WifiTxVector &txVector)
Called when the BlockAck timeout expires.
Ptr< WifiMpdu > GetBar(AcIndex ac, std::optional< uint8_t > optTid=std::nullopt, std::optional< Mac48Address > optAddress=std::nullopt)
Get the next BlockAckRequest or MU-BAR Trigger Frame to send, if any.
virtual Time GetPsduDurationId(Time txDuration, const WifiTxParameters &txParams) const
Compute how to set the Duration/ID field of PSDUs that do not include fragments.
virtual bool NeedSetupBlockAck(Mac48Address recipient, uint8_t tid)
A Block Ack agreement needs to be established with the given recipient for the given TID if it does n...
void TransmissionSucceeded() override
Take necessary actions upon a transmission success.
virtual bool SendMpduFromBaManager(Ptr< WifiMpdu > mpdu, Time availableTime, bool initialFrame)
If the given MPDU contains a BlockAckReq frame (the duration of which plus the response fits within t...
Ptr< MpduAggregator > GetMpduAggregator() const
Returns the aggregator used to construct A-MPDU subframes.
virtual bool IsWithinLimitsIfAggregateMsdu(Ptr< const WifiMpdu > msdu, const WifiTxParameters &txParams, Time ppduDurationLimit) const
Check if the PSDU obtained by aggregating the given MSDU to the PSDU specified by the given TX parame...
virtual bool IsWithinAmpduSizeLimit(uint32_t ampduSize, Mac48Address receiver, uint8_t tid, WifiModulationClass modulation) const
Check whether an A-MPDU of the given size meets the constraint on the maximum size for A-MPDUs sent t...
void SetWifiMac(const Ptr< WifiMac > mac) override
Set the MAC layer to use.
void ForwardMpduDown(Ptr< WifiMpdu > mpdu, WifiTxVector &txVector) override
Forward an MPDU down to the PHY layer.
Ptr< MsduAggregator > GetMsduAggregator() const
Returns the aggregator used to construct A-MSDU subframes.
void SendPsduWithProtection(Ptr< WifiPsdu > psdu, WifiTxParameters &txParams)
Send a PSDU (A-MPDU or BlockAckReq frame) requesting a BlockAck frame or a BlockAckReq frame followed...
void NotifyReceivedNormalAck(Ptr< WifiMpdu > mpdu) override
Notify other components that an MPDU was acknowledged.
void EndReceiveAmpdu(Ptr< const WifiPsdu > psdu, const RxSignalInfo &rxSignalInfo, const WifiTxVector &txVector, const std::vector< bool > &perMpduStatus) override
This method is called when the reception of an A-MPDU including multiple MPDUs is completed.
void RetransmitMpduAfterMissedAck(Ptr< WifiMpdu > mpdu) const override
Retransmit an MPDU that was not acknowledged.
void DoDispose() override
Destructor implementation.
static TypeId GetTypeId()
Get the type ID.
bool StartFrameExchange(Ptr< QosTxop > edca, Time availableTime, bool initialFrame) override
Start a frame exchange (including protection frames and acknowledgment frames as needed) that fits wi...
WifiTxParameters m_txParams
the TX parameters for the current frame
bool IsWithinLimitsIfAddMpdu(Ptr< const WifiMpdu > mpdu, const WifiTxParameters &txParams, Time ppduDurationLimit) const override
Check if the PSDU obtained by aggregating the given MPDU to the PSDU specified by the given TX parame...
void SendPsdu()
Send the current PSDU, which can be acknowledged by a BlockAck frame or followed by a BlockAckReq fra...
virtual uint16_t GetSupportedBaBufferSize() const
Get the maximum supported buffer size for a Block Ack agreement.
virtual bool TryAggregateMsdu(Ptr< const WifiMpdu > msdu, WifiTxParameters &txParams, Time availableTime) const
Check if aggregating an MSDU to the current MPDU (as specified by the given TX parameters) does not v...
virtual void NotifyTxToEdca(Ptr< const WifiPsdu > psdu) const
Notify the transmission of the given PSDU to the EDCAF associated with the AC the PSDU belongs to.
virtual bool SendDataFrame(Ptr< WifiMpdu > peekedItem, Time availableTime, bool initialFrame)
Given a non-broadcast QoS data frame, prepare the PSDU to transmit by attempting A-MSDU and A-MPDU ag...
void NotifyPacketDiscarded(Ptr< const WifiMpdu > mpdu) override
Pass the given MPDU, discarded because of the max retry limit was reached, to the MPDU dropped callba...
virtual void ForwardPsduDown(Ptr< const WifiPsdu > psdu, WifiTxVector &txVector)
Forward a PSDU down to the PHY layer.
void CalculateAcknowledgmentTime(WifiAcknowledgment *acknowledgment) const override
Calculate the time required to acknowledge a frame according to the given acknowledgment method.
void DequeuePsdu(Ptr< const WifiPsdu > psdu)
Dequeue the MPDUs of the given PSDU from the queue in which they are stored.
void ReleaseSequenceNumbers(Ptr< const WifiPsdu > psdu) const override
Make the sequence numbers of MPDUs included in the given PSDU available again if the MPDUs have never...
virtual void MissedBlockAck(Ptr< WifiPsdu > psdu, const WifiTxVector &txVector, bool &resetCw)
Take necessary actions when a BlockAck is missed, such as scheduling a BlockAckReq frame or the retra...
Ptr< MsduAggregator > m_msduAggregator
A-MSDU aggregator.
std::pair< Mac48Address, uint8_t > AgreementKey
agreement key typedef (MAC address and TID)
void SendBlockAck(const RecipientBlockAckAgreement &agreement, Time durationId, WifiTxVector &blockAckTxVector, double rxSnr)
Create a BlockAck frame with header equal to blockAck and start its transmission.
an EUI-48 address
Definition: mac48-address.h:46
bool IsGroup() const
Implement the header for management frames of type Add Block Ack request.
Definition: mgt-headers.h:1511
void SetBufferSize(uint16_t size)
Set buffer size.
void SetDelayedBlockAck()
Enable delayed BlockAck.
void SetAmsduSupport(bool supported)
Enable or disable A-MSDU support.
void SetImmediateBlockAck()
Enable immediate BlockAck.
uint16_t GetTimeout() const
Return the timeout.
uint8_t GetTid() const
Return the Traffic ID (TID).
uint16_t GetStartingSequence() const
Return the starting sequence number.
bool IsAmsduSupported() const
Return whether A-MSDU capability is supported.
bool IsImmediateBlockAck() const
Return whether the Block Ack policy is immediate Block Ack.
void SetTimeout(uint16_t timeout)
Set timeout.
void SetTid(uint8_t tid)
Set Traffic ID (TID).
void SetStartingSequence(uint16_t seq)
Set the starting sequence number.
Implement the header for management frames of type Add Block Ack response.
Definition: mgt-headers.h:1642
void SetTid(uint8_t tid)
Set Traffic ID (TID).
void SetTimeout(uint16_t timeout)
Set timeout.
void SetBufferSize(uint16_t size)
Set buffer size.
void SetStatusCode(StatusCode code)
Set the status code.
uint8_t GetTid() const
Return the Traffic ID (TID).
void SetAmsduSupport(bool supported)
Enable or disable A-MSDU support.
uint16_t GetTimeout() const
Return the timeout.
void SetDelayedBlockAck()
Enable delayed BlockAck.
void SetImmediateBlockAck()
Enable immediate BlockAck.
Implement the header for management frames of type Delete Block Ack.
Definition: mgt-headers.h:1761
void SetTid(uint8_t tid)
Set Traffic ID (TID).
void SetByRecipient()
Un-set the initiator bit in the DELBA.
uint8_t GetTid() const
Return the Traffic ID (TID).
bool IsByOriginator() const
Check if the initiator bit in the DELBA is set.
void SetByOriginator()
Set the initiator bit in the DELBA.
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:78
QosFrameExchangeManager handles the frame exchange sequences for QoS stations.
void ReceiveMpdu(Ptr< const WifiMpdu > mpdu, RxSignalInfo rxSignalInfo, const WifiTxVector &txVector, bool inAmpdu) override
This method handles the reception of an MPDU (possibly included in an A-MPDU)
void TransmissionFailed() override
Take necessary actions upon a transmission failure.
virtual bool StartFrameExchange(Ptr< QosTxop > edca, Time availableTime, bool initialFrame)
Start a frame exchange (including protection frames and acknowledgment frames as needed) that fits wi...
Ptr< QosTxop > m_edca
the EDCAF that gained channel access
virtual Ptr< WifiMpdu > CreateAliasIfNeeded(Ptr< WifiMpdu > mpdu) const
Create an alias of the given MPDU for transmission by this Frame Exchange Manager.
void TransmissionSucceeded() override
Take necessary actions upon a transmission success.
bool m_setQosQueueSize
whether to set the Queue Size subfield of the QoS Control field of QoS data frames
virtual bool IsWithinSizeAndTimeLimits(uint32_t ppduPayloadSize, Mac48Address receiver, const WifiTxParameters &txParams, Time ppduDurationLimit) const
Check whether the transmission time of the frame being built (as described by the given TX parameters...
void DoDispose() override
Destructor implementation.
Ptr< BlockAckManager > GetBaManager()
Get the Block Ack Manager associated with this QosTxop.
Definition: qos-txop.cc:261
AcIndex GetAccessCategory() const
Get the access category of this object.
Definition: qos-txop.cc:766
void AddBaResponseTimeout(Mac48Address recipient, uint8_t tid)
Callback when ADDBA response is not received after timeout.
Definition: qos-txop.cc:706
virtual Time GetRemainingTxop(uint8_t linkId) const
Return the remaining duration in the current TXOP on the given link.
Definition: qos-txop.cc:591
void ResetBa(Mac48Address recipient, uint8_t tid)
Reset BA agreement after BA negotiation failed.
Definition: qos-txop.cc:719
Ptr< WifiMpdu > PrepareBlockAckRequest(Mac48Address recipient, uint8_t tid) const
Definition: qos-txop.cc:279
Maintains the scoreboard and the receive reordering buffer used by a recipient of a Block Ack agreeme...
void FillBlockAckBitmap(CtrlBAckResponseHeader *blockAckHeader, std::size_t index=0) const
Set the Starting Sequence Number subfield of the Block Ack Starting Sequence Control subfield of the ...
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:568
Introspection did not find any typical Config paths.
Definition: snr-tag.h:35
void Set(double snr)
Set the SNR to the given value.
Definition: snr-tag.cc:84
double Get() const
Return the SNR value.
Definition: snr-tag.cc:90
Status code for association response.
Definition: status-code.h:32
void SetSuccess()
Set success bit to 0 (success).
Definition: status-code.cc:30
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
static Time Min()
Minimum representable Time Not to be confused with Min(Time,Time).
Definition: nstime.h:286
bool IsStrictlyNegative() const
Exactly equivalent to t < 0.
Definition: nstime.h:341
bool IsZero() const
Exactly equivalent to t == 0.
Definition: nstime.h:314
Time GetTxopLimit() const
Return the TXOP limit.
Definition: txop.cc:473
void UpdateFailedCw(uint8_t linkId)
Update the value of the CW variable for the given link to take into account a transmission failure.
Definition: txop.cc:300
Ptr< WifiMacQueue > GetWifiMacQueue() const
Return the packet queue associated with this Txop.
Definition: txop.cc:220
void ResetCw(uint8_t linkId)
Update the value of the CW variable for the given link to take into account a transmission success or...
Definition: txop.cc:291
virtual void Queue(Ptr< Packet > packet, const WifiMacHeader &hdr)
Definition: txop.cc:505
a unique identifier for an interface.
Definition: type-id.h:60
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:935
static void SetQosAckPolicy(Ptr< WifiMpdu > item, const WifiAcknowledgment *acknowledgment)
Set the QoS Ack policy for the given MPDU, which must be a QoS data frame.
See IEEE 802.11 chapter 7.3.1.11 Header format: | category: 1 | action value: 1 |.
Definition: mgt-headers.h:1279
void SetAction(CategoryValue type, ActionValue action)
Set action for this Action header.
CategoryValue GetCategory() const
Return the category value.
ActionValue GetAction() const
Return the action value.
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.
bool IsCts() const
Return true if the header is a CTS header.
Mac48Address GetAddr1() const
Return the address in the Address 1 field.
uint16_t GetSequenceNumber() const
Return the sequence number of the header.
bool IsRetry() const
Return if the Retry bit is set.
bool IsCtl() const
Return true if the Type is Control.
Time GetDuration() const
Return the duration from the Duration/ID field (Time object).
void SetDsNotFrom()
Un-set the From DS bit in the Frame Control field.
bool IsQosEosp() const
Return if the end of service period (EOSP) is set.
void SetAddr1(Mac48Address address)
Fill the Address 1 field with the given address.
void SetQosQueueSize(uint8_t size)
Set the Queue Size subfield in the QoS control field.
bool IsBlockAck() const
Return true if the header is a BlockAck header.
void SetType(WifiMacType type, bool resetToDsFromDs=true)
Set Type/Subtype values with the correct values depending on the given type.
Mac48Address GetAddr2() const
Return the address in the Address 2 field.
bool HasData() const
Return true if the header type is DATA and is not DATA_NULL.
QosAckPolicy GetQosAckPolicy() const
Return the QoS Ack policy in the QoS control field.
void SetAddr2(Mac48Address address)
Fill the Address 2 field with the given address.
bool IsQosData() const
Return true if the Type is DATA and Subtype is one of the possible values for QoS Data.
void SetQosEosp()
Set the end of service period (EOSP) bit in the QoS control field.
void SetAddr3(Mac48Address address)
Fill the Address 3 field with the given address.
void SetDsNotTo()
Un-set the To DS bit in the Frame Control field.
QosAckPolicy
Ack policy for QoS frames.
std::optional< Mac48Address > GetMldAddress(const Mac48Address &remoteAddr) const
Definition: wifi-mac.cc:1236
TypeOfStation GetTypeOfStation() const
Return the type of station.
Definition: wifi-mac.cc:418
RecipientAgreementOptConstRef GetBaAgreementEstablishedAsRecipient(Mac48Address originator, uint8_t tid) const
Definition: wifi-mac.cc:1297
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:536
OriginatorAgreementOptConstRef GetBaAgreementEstablishedAsOriginator(Mac48Address recipient, uint8_t tid) const
Definition: wifi-mac.cc:1283
Mac48Address GetAddress() const
Definition: wifi-mac.cc:443
Ptr< QosTxop > GetQosTxop(AcIndex ac) const
Accessor for a specified EDCA object.
Definition: wifi-mac.cc:490
void Send(Ptr< const WifiPsdu > psdu, const WifiTxVector &txVector)
This function is a wrapper for the Send variant that accepts a WifiConstPsduMap as first argument.
Definition: wifi-phy.cc:1693
Time GetSlot() const
Return the slot duration for this PHY.
Definition: wifi-phy.cc:786
Time GetSifs() const
Return the Short Interframe Space (SIFS) for this PHY.
Definition: wifi-phy.cc:774
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition: wifi-phy.cc:1480
WifiPhyBand GetPhyBand() const
Get the configured Wi-Fi band.
Definition: wifi-phy.cc:996
static Time CalculatePhyPreambleAndHeaderDuration(const WifiTxVector &txVector)
Definition: wifi-phy.cc:1473
std::set< uint8_t > GetTids() const
Get the set of TIDs of the QoS Data frames included in the PSDU.
Definition: wifi-psdu.cc:178
const WifiMacHeader & GetHeader(std::size_t i) const
Get the header of the i-th MPDU.
Definition: wifi-psdu.cc:279
std::vector< Ptr< WifiMpdu > >::const_iterator begin() const
Return a const iterator to the first MPDU.
Definition: wifi-psdu.cc:333
uint32_t GetSize() const
Return the size of the PSDU in bytes.
Definition: wifi-psdu.cc:273
Mac48Address GetAddr1() const
Get the Receiver Address (RA), which is common to all the MPDUs.
Definition: wifi-psdu.cc:113
void SetDuration(Time duration)
Set the Duration/ID field on all the MPDUs.
Definition: wifi-psdu.cc:168
std::size_t GetNMpdus() const
Return the number of MPDUs constituting the PSDU.
Definition: wifi-psdu.cc:327
WifiMacHeader::QosAckPolicy GetAckPolicyForTid(uint8_t tid) const
Get the QoS Ack Policy of the QoS Data frames included in the PSDU that have the given TID.
Definition: wifi-psdu.cc:192
void ReportDataFailed(Ptr< const WifiMpdu > mpdu)
Should be invoked whenever the AckTimeout associated to a transmission attempt expires.
void ReportFinalDataFailed(Ptr< const WifiMpdu > mpdu)
Should be invoked after calling ReportDataFailed if NeedRetransmission returns false.
std::optional< Mac48Address > GetAffiliatedStaAddress(const Mac48Address &mldAddress) const
Get the address of the remote station operating on this link and affiliated with the MLD having the g...
void ReportRtsOk(const WifiMacHeader &header, double ctsSnr, WifiMode ctsMode, double rtsSnr)
Should be invoked whenever we receive the CTS associated to an RTS we just sent.
void ReportRxOk(Mac48Address address, RxSignalInfo rxSignalInfo, WifiTxVector txVector)
void ReportAmpduTxStatus(Mac48Address address, uint16_t nSuccessfulMpdus, uint16_t nFailedMpdus, double rxSnr, double dataSnr, WifiTxVector dataTxVector)
Typically called per A-MPDU, either when a Block ACK was successfully received or when a BlockAckTime...
bool GetHtSupported() const
Return whether the device has HT capability support enabled.
bool GetVhtSupported() const
Return whether the device has VHT capability support enabled.
WifiTxVector GetDataTxVector(const WifiMacHeader &header, uint16_t allowedWidth)
std::optional< Mac48Address > GetMldAddress(const Mac48Address &address) const
Get the address of the MLD the given station is affiliated with, if any.
This class stores the TX parameters (TX vector, protection mechanism, acknowledgment mechanism,...
uint32_t GetSizeIfAddMpdu(Ptr< const WifiMpdu > mpdu) const
Get the size in bytes of the frame in case the given MPDU is added.
std::pair< uint32_t, uint32_t > GetSizeIfAggregateMsdu(Ptr< const WifiMpdu > msdu) const
Get the size in bytes of the frame in case the given MSDU is aggregated.
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.
void AggregateMsdu(Ptr< const WifiMpdu > msdu)
Record that an MSDU is being aggregated to the last MPDU added to the frame that hase the same receiv...
void Clear()
Reset the TX parameters.
bool IsRunning() const
Return true if the timer is running.
void Cancel()
Cancel the timer.
void Set(Reason reason, const Time &delay, MEM mem_ptr, OBJ obj, Args... args)
This method is called when a frame soliciting a response is transmitted.
Reason GetReason() const
Get the reason why the timer was started.
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
WifiMode GetMode(uint16_t staId=SU_STA_ID) const
If this TX vector is associated with an SU PPDU, return the selected payload transmission mode.
void SetAggregation(bool aggregation)
Sets if PSDU contains A-MPDU.
WifiModulationClass GetModulationClass() const
Get the modulation class specified by this TXVECTOR.
#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_ABORT_IF(cond)
Abnormal program termination if a condition is true.
Definition: abort.h:76
#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_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:46
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1360
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1336
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:195
WifiModulationClass
This enumeration defines the modulation classes per (Table 10-6 "Modulation classes"; IEEE 802....
AcIndex
This enumeration defines the Access Categories as an enumeration with values corresponding to the AC ...
Definition: qos-utils.h:72
@ WIFI_MOD_CLASS_HT
HT (Clause 19)
Every class exported by the ns3 library is enclosed in the ns3 namespace.
U * PeekPointer(const Ptr< U > &p)
Definition: ptr.h:488
@ STA
Definition: wifi-mac.h:62
uint32_t GetBlockAckRequestSize(BlockAckReqType type)
Return the total BlockAckRequest size (including FCS trailer).
Definition: wifi-utils.cc:76
@ WIFI_MAC_MGT_ACTION
@ WIFI_MAC_CTL_BACKRESP
@ WIFI_QOSDATA_UNICAST_QUEUE
static constexpr uint16_t SEQNO_SPACE_SIZE
Size of the space of sequence numbers.
Definition: wifi-utils.h:133
uint32_t GetBlockAckSize(BlockAckType type)
Return the total BlockAck size (including FCS trailer).
Definition: wifi-utils.cc:66
std::tuple< WifiContainerQueueType, Mac48Address, std::optional< uint8_t > > WifiContainerQueueId
Tuple (queue type, Address, TID) identifying a container queue.
ns3::Time timeout
RxSignalInfo structure containing info on the received signal.
Definition: phy-entity.h:70
double snr
SNR in linear scale.
Definition: phy-entity.h:71
WifiAcknowledgment is an abstract base struct.
Time acknowledgmentTime
time required by the acknowledgment method
const Method method
acknowledgment method
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.
WifiNoProtection specifies that no protection method is used.
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
uint32_t ampduSize
the size in bytes of the A-MPDU if multiple MPDUs have been added, and zero otherwise
typedef for union of different ActionValues
Definition: mgt-headers.h:1444
BlockAckActionValue blockAck
block ack
Definition: mgt-headers.h:1446