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/assert.h"
24#include "ns3/ctrl-headers.h"
25#include "ns3/log.h"
26#include "ns3/mgt-headers.h"
27#include "ns3/recipient-block-ack-agreement.h"
28#include "ns3/snr-tag.h"
29#include "ns3/sta-wifi-mac.h"
30#include "ns3/wifi-mac-queue.h"
31#include "ns3/wifi-utils.h"
32
33#include <array>
34#include <optional>
35
36#undef NS_LOG_APPEND_CONTEXT
37#define NS_LOG_APPEND_CONTEXT std::clog << "[link=" << +m_linkId << "][mac=" << m_self << "] "
38
39namespace ns3
40{
41
42NS_LOG_COMPONENT_DEFINE("HtFrameExchangeManager");
43
44NS_OBJECT_ENSURE_REGISTERED(HtFrameExchangeManager);
45
46TypeId
48{
49 static TypeId tid = TypeId("ns3::HtFrameExchangeManager")
51 .AddConstructor<HtFrameExchangeManager>()
52 .SetGroupName("Wifi");
53 return tid;
54}
55
57{
58 NS_LOG_FUNCTION(this);
59 m_msduAggregator = CreateObject<MsduAggregator>();
60 m_mpduAggregator = CreateObject<MpduAggregator>();
61}
62
64{
66}
67
68void
70{
71 NS_LOG_FUNCTION(this);
72 m_pendingAddBaResp.clear();
73 m_msduAggregator = nullptr;
74 m_mpduAggregator = nullptr;
75 m_psdu = nullptr;
78}
79
80void
82{
83 m_msduAggregator->SetWifiMac(mac);
84 m_mpduAggregator->SetWifiMac(mac);
86}
87
90{
91 return m_msduAggregator;
92}
93
96{
97 return m_mpduAggregator;
98}
99
102{
103 return m_mac->GetQosTxop(tid)->GetBaManager();
104}
105
106bool
108{
109 Ptr<QosTxop> qosTxop = m_mac->GetQosTxop(tid);
110 bool establish;
111
112 if (!GetWifiRemoteStationManager()->GetHtSupported(recipient))
113 {
114 establish = false;
115 }
116 else if (auto agreement = qosTxop->GetBaManager()->GetAgreementAsOriginator(recipient, tid);
117 agreement && !agreement->get().IsReset())
118 {
119 establish = false;
120 }
121 else
122 {
123 WifiContainerQueueId queueId{WIFI_QOSDATA_QUEUE, WIFI_UNICAST, recipient, tid};
124 uint32_t packets = qosTxop->GetWifiMacQueue()->GetNPackets(queueId);
125 establish =
126 ((qosTxop->GetBlockAckThreshold() > 0 && packets >= qosTxop->GetBlockAckThreshold()) ||
127 (m_mpduAggregator->GetMaxAmpduSize(recipient, tid, WIFI_MOD_CLASS_HT) > 0 &&
128 packets > 1) ||
130 }
131
132 NS_LOG_FUNCTION(this << recipient << +tid << establish);
133 return establish;
134}
135
136bool
138 uint8_t tid,
139 uint16_t startingSeq,
140 uint16_t timeout,
141 bool immediateBAck,
142 Time availableTime)
143{
144 NS_LOG_FUNCTION(this << dest << +tid << startingSeq << timeout << immediateBAck
145 << availableTime);
146 NS_LOG_DEBUG("Send ADDBA request to " << dest);
147
148 WifiMacHeader hdr;
150 // use the remote link address if dest is an MLD address
152 hdr.SetAddr1(addr1 ? *addr1 : dest);
153 hdr.SetAddr2(m_self);
154 hdr.SetAddr3(m_bssid);
155 hdr.SetDsNotTo();
156 hdr.SetDsNotFrom();
157
158 WifiActionHeader actionHdr;
161 actionHdr.SetAction(WifiActionHeader::BLOCK_ACK, action);
162
163 Ptr<Packet> packet = Create<Packet>();
164 // Setting ADDBARequest header
166 reqHdr.SetAmsduSupport(true);
167 if (immediateBAck)
168 {
169 reqHdr.SetImmediateBlockAck();
170 }
171 else
172 {
173 reqHdr.SetDelayedBlockAck();
174 }
175 reqHdr.SetTid(tid);
176 /* For now we don't use buffer size field in the ADDBA request frame. The recipient
177 * will choose how many packets it can receive under block ack.
178 */
179 reqHdr.SetBufferSize(0);
180 reqHdr.SetTimeout(timeout);
181 // set the starting sequence number for the BA agreement
182 reqHdr.SetStartingSequence(startingSeq);
183
184 GetBaManager(tid)->CreateOriginatorAgreement(reqHdr, dest);
185
186 packet->AddHeader(reqHdr);
187 packet->AddHeader(actionHdr);
188
189 Ptr<WifiMpdu> mpdu = Create<WifiMpdu>(packet, hdr);
190
191 // get the sequence number for the ADDBA Request management frame
192 uint16_t sequence = m_txMiddle->GetNextSequenceNumberFor(&mpdu->GetHeader());
193 mpdu->GetHeader().SetSequenceNumber(sequence);
194
195 WifiTxParameters txParams;
196 txParams.m_txVector =
198 if (!TryAddMpdu(mpdu, txParams, availableTime))
199 {
200 NS_LOG_DEBUG("Not enough time to send the ADDBA Request frame");
201 return false;
202 }
203
204 // Wifi MAC queue scheduler is expected to prioritize management frames
205 m_mac->GetQosTxop(tid)->GetWifiMacQueue()->Enqueue(mpdu);
206 SendMpduWithProtection(mpdu, txParams);
207 return true;
208}
209
210void
212 Mac48Address originator)
213{
214 NS_LOG_FUNCTION(this << originator);
215 WifiMacHeader hdr;
217 hdr.SetAddr1(originator);
218 hdr.SetAddr2(m_self);
219 hdr.SetAddr3(m_bssid);
220 hdr.SetDsNotFrom();
221 hdr.SetDsNotTo();
222
224 StatusCode code;
225 code.SetSuccess();
226 respHdr.SetStatusCode(code);
227 // Here a control about queues type?
228 respHdr.SetAmsduSupport(reqHdr->IsAmsduSupported());
229
230 if (reqHdr->IsImmediateBlockAck())
231 {
232 respHdr.SetImmediateBlockAck();
233 }
234 else
235 {
236 respHdr.SetDelayedBlockAck();
237 }
238 auto tid = reqHdr->GetTid();
239 respHdr.SetTid(tid);
240
242 respHdr.SetTimeout(reqHdr->GetTimeout());
243
244 WifiActionHeader actionHdr;
247 actionHdr.SetAction(WifiActionHeader::BLOCK_ACK, action);
248
249 Ptr<Packet> packet = Create<Packet>();
250 packet->AddHeader(respHdr);
251 packet->AddHeader(actionHdr);
252
253 // Get the MLD address of the originator, if an ML setup was performed
254 if (auto originatorMld = GetWifiRemoteStationManager()->GetMldAddress(originator))
255 {
256 originator = *originatorMld;
257 }
258 bool htSupported = GetWifiRemoteStationManager()->GetHtSupported() &&
260 GetBaManager(tid)->CreateRecipientAgreement(respHdr,
261 originator,
262 reqHdr->GetStartingSequence(),
263 htSupported,
264 m_rxMiddle);
265
266 auto agreement = GetBaManager(tid)->GetAgreementAsRecipient(originator, tid);
267 NS_ASSERT(agreement);
268 if (respHdr.GetTimeout() != 0)
269 {
270 Time timeout = MicroSeconds(1024 * agreement->get().GetTimeout());
271
272 agreement->get().m_inactivityEvent =
275 this,
276 originator,
277 tid,
278 false);
279 }
280
281 auto mpdu = Create<WifiMpdu>(packet, hdr);
282
283 /*
284 * It is possible (though, unlikely) that at this point there are other ADDBA_RESPONSE frame(s)
285 * in the MAC queue. This may happen if the recipient receives an ADDBA_REQUEST frame, enqueues
286 * an ADDBA_RESPONSE frame, but is not able to successfully transmit it before the timer to
287 * wait for ADDBA_RESPONSE expires at the originator. The latter may then send another
288 * ADDBA_REQUEST frame, which triggers the creation of another ADDBA_RESPONSE frame.
289 * To avoid sending unnecessary ADDBA_RESPONSE frames, we keep track of the previously enqueued
290 * ADDBA_RESPONSE frame (if any), dequeue it and replace it with the new ADDBA_RESPONSE frame.
291 */
292
293 // remove any pending ADDBA_RESPONSE frame
294 AgreementKey key(originator, tid);
295 if (auto it = m_pendingAddBaResp.find(key); it != m_pendingAddBaResp.end())
296 {
297 NS_ASSERT_MSG(it->second, "The pointer to the pending ADDBA_RESPONSE cannot be null");
298 DequeueMpdu(it->second);
299 m_pendingAddBaResp.erase(it);
300 }
301 // store the new ADDBA_RESPONSE frame
302 m_pendingAddBaResp[key] = mpdu;
303
304 // It is unclear which queue this frame should go into. For now we
305 // bung it into the queue corresponding to the TID for which we are
306 // establishing an agreement, and push it to the head.
307 // Wifi MAC queue scheduler is expected to prioritize management frames
308 m_mac->GetQosTxop(tid)->Queue(mpdu);
309}
310
311uint16_t
313{
314 return 64;
315}
316
317void
318HtFrameExchangeManager::SendDelbaFrame(Mac48Address addr, uint8_t tid, bool byOriginator)
319{
320 NS_LOG_FUNCTION(this << addr << +tid << byOriginator);
321 WifiMacHeader hdr;
323 // use the remote link address if addr is an MLD address
324 hdr.SetAddr1(GetWifiRemoteStationManager()->GetAffiliatedStaAddress(addr).value_or(addr));
325 hdr.SetAddr2(m_self);
326 hdr.SetAddr3(m_bssid);
327 hdr.SetDsNotTo();
328 hdr.SetDsNotFrom();
329
330 MgtDelBaHeader delbaHdr;
331 delbaHdr.SetTid(tid);
332 if (byOriginator)
333 {
334 delbaHdr.SetByOriginator();
335 GetBaManager(tid)->DestroyOriginatorAgreement(addr, tid);
336 }
337 else
338 {
339 delbaHdr.SetByRecipient();
340 GetBaManager(tid)->DestroyRecipientAgreement(addr, tid);
341 }
342
343 WifiActionHeader actionHdr;
345 action.blockAck = WifiActionHeader::BLOCK_ACK_DELBA;
346 actionHdr.SetAction(WifiActionHeader::BLOCK_ACK, action);
347
348 Ptr<Packet> packet = Create<Packet>();
349 packet->AddHeader(delbaHdr);
350 packet->AddHeader(actionHdr);
351
352 m_mac->GetQosTxop(tid)->GetWifiMacQueue()->Enqueue(Create<WifiMpdu>(packet, hdr));
353}
354
355bool
356HtFrameExchangeManager::StartFrameExchange(Ptr<QosTxop> edca, Time availableTime, bool initialFrame)
357{
358 NS_LOG_FUNCTION(this << edca << availableTime << initialFrame);
359
360 // First, check if there is a BAR to be transmitted
361 if (auto mpdu = GetBar(edca->GetAccessCategory());
362 mpdu && SendMpduFromBaManager(mpdu, availableTime, initialFrame))
363 {
364 return true;
365 }
366
367 Ptr<WifiMpdu> peekedItem = edca->PeekNextMpdu(m_linkId);
368
369 // Even though channel access is requested when the queue is not empty, at
370 // the time channel access is granted the lifetime of the packet might be
371 // expired and the queue might be empty.
372 if (!peekedItem)
373 {
374 NS_LOG_DEBUG("No frames available for transmission");
375 return false;
376 }
377
378 const WifiMacHeader& hdr = peekedItem->GetHeader();
379 // setup a Block Ack agreement if needed
380 if (hdr.IsQosData() && !hdr.GetAddr1().IsGroup() &&
382 {
383 // if the peeked MPDU has been already transmitted, use its sequence number
384 // as the starting sequence number for the BA agreement, otherwise use the
385 // next available sequence number
386 uint16_t startingSeq =
387 (hdr.IsRetry()
388 ? hdr.GetSequenceNumber()
389 : m_txMiddle->GetNextSeqNumberByTidAndAddress(hdr.GetQosTid(), hdr.GetAddr1()));
390 return SendAddBaRequest(hdr.GetAddr1(),
391 hdr.GetQosTid(),
392 startingSeq,
393 edca->GetBlockAckInactivityTimeout(),
394 true,
395 availableTime);
396 }
397
398 // Use SendDataFrame if we can try aggregation
399 if (hdr.IsQosData() && !hdr.GetAddr1().IsGroup() && !peekedItem->IsFragment() &&
400 !GetWifiRemoteStationManager()->NeedFragmentation(peekedItem =
401 CreateAliasIfNeeded(peekedItem)))
402 {
403 return SendDataFrame(peekedItem, availableTime, initialFrame);
404 }
405
406 // Use the QoS FEM to transmit the frame in all the other cases, i.e.:
407 // - the frame is not a QoS data frame
408 // - the frame is a broadcast QoS data frame
409 // - the frame is a fragment
410 // - the frame must be fragmented
411 return QosFrameExchangeManager::StartFrameExchange(edca, availableTime, initialFrame);
412}
413
416 std::optional<uint8_t> optTid,
417 std::optional<Mac48Address> optAddress)
418{
419 NS_LOG_FUNCTION(this << +ac << optTid.has_value() << optAddress.has_value());
420 NS_ASSERT_MSG(optTid.has_value() == optAddress.has_value(),
421 "Either both or none of TID and address must be provided");
422
423 // remove all expired MPDUs from the MAC queue, so that
424 // BlockAckRequest frames (if needed) are scheduled
425 auto queue = m_mac->GetTxopQueue(ac);
426 queue->WipeAllExpiredMpdus();
427
428 Ptr<WifiMpdu> bar;
429 Ptr<WifiMpdu> prevBar;
430 Ptr<WifiMpdu> selectedBar;
431
432 // we could iterate over all the scheduler's queues and ignore those that do not contain
433 // control frames, but it's more efficient to peek frames until we get frames that are
434 // not control frames, given that control frames have the highest priority
435 while ((bar = queue->PeekFirstAvailable(m_linkId, prevBar)) && bar && bar->GetHeader().IsCtl())
436 {
437 if (bar->GetHeader().IsBlockAckReq())
438 {
440 bar->GetPacket()->PeekHeader(reqHdr);
441 auto tid = reqHdr.GetTidInfo();
442 Mac48Address recipient = bar->GetHeader().GetAddr1();
443 auto recipientMld = m_mac->GetMldAddress(recipient);
444
445 // the scheduler should not return a BlockAckReq that cannot be sent on this link:
446 // either the TA address is the address of this link or it is the MLD address and
447 // the RA field is the MLD address of a device we can communicate with on this link
448 NS_ASSERT_MSG(bar->GetHeader().GetAddr2() == m_self ||
449 (bar->GetHeader().GetAddr2() == m_mac->GetAddress() && recipientMld &&
450 GetWifiRemoteStationManager()->GetAffiliatedStaAddress(recipient)),
451 "Cannot use link " << +m_linkId << " to send BAR: " << *bar);
452
453 if (optAddress &&
454 (GetWifiRemoteStationManager()->GetMldAddress(*optAddress).value_or(*optAddress) !=
455 GetWifiRemoteStationManager()->GetMldAddress(recipient).value_or(recipient) ||
456 optTid != tid))
457 {
458 NS_LOG_DEBUG("BAR " << *bar
459 << " cannot be returned because it is not addressed"
460 " to the given station for the given TID");
461 prevBar = bar;
462 continue;
463 }
464
465 auto agreement = m_mac->GetBaAgreementEstablishedAsOriginator(recipient, tid);
466 if (!agreement)
467 {
468 NS_LOG_DEBUG("BA agreement with " << recipient << " for TID=" << +tid
469 << " was torn down");
470 queue->Remove(bar);
471 continue;
472 }
473 // update BAR if the starting sequence number changed
474 if (auto seqNo = agreement->get().GetStartingSequence();
475 reqHdr.GetStartingSequence() != seqNo)
476 {
477 reqHdr.SetStartingSequence(seqNo);
478 Ptr<Packet> packet = Create<Packet>();
479 packet->AddHeader(reqHdr);
480 auto updatedBar = Create<WifiMpdu>(packet, bar->GetHeader(), bar->GetTimestamp());
481 queue->Replace(bar, updatedBar);
482 bar = updatedBar;
483 }
484 // bar is the BlockAckReq to send
485 selectedBar = bar;
486
487 // if the selected BAR is intended to be sent on this specific link and the recipient
488 // is an MLD, remove the BAR (if any) for this BA agreement that can be sent on any
489 // link (because a BAR that can be sent on any link to a recipient is no longer
490 // needed after sending a BAR to that recipient on this link)
491 if (bar->GetHeader().GetAddr2() == m_self && recipientMld)
492 {
495 *recipientMld,
496 std::nullopt};
497 Ptr<WifiMpdu> otherBar;
498 while ((otherBar = queue->PeekByQueueId(queueId, otherBar)))
499 {
500 if (otherBar->GetHeader().IsBlockAckReq())
501 {
502 CtrlBAckRequestHeader otherReqHdr;
503 otherBar->GetPacket()->PeekHeader(otherReqHdr);
504 if (otherReqHdr.GetTidInfo() == tid)
505 {
506 queue->Remove(otherBar);
507 break;
508 }
509 }
510 }
511 }
512 break;
513 }
514 if (bar->GetHeader().IsTrigger() && !optAddress && !selectedBar)
515 {
516 return bar;
517 }
518 // not a BAR nor a Trigger Frame, continue
519 prevBar = bar;
520 }
521
522 if (!selectedBar)
523 {
524 // check if we can send a BAR to a recipient to which a BAR can only be sent if data queued
525 auto baManager = m_mac->GetQosTxop(ac)->GetBaManager();
526 for (const auto& [recipient, tid] : baManager->GetSendBarIfDataQueuedList())
527 {
528 if (queue->PeekByTidAndAddress(tid, recipient))
529 {
530 auto [reqHdr, hdr] = m_mac->GetQosTxop(ac)->PrepareBlockAckRequest(recipient, tid);
531 auto pkt = Create<Packet>();
532 pkt->AddHeader(reqHdr);
533 selectedBar = Create<WifiMpdu>(pkt, hdr);
534 baManager->RemoveFromSendBarIfDataQueuedList(recipient, tid);
535 queue->Enqueue(selectedBar);
536 break;
537 }
538 }
539 }
540
541 if (selectedBar && selectedBar->GetHeader().GetAddr2() != m_self)
542 {
543 // the selected BAR has MLD addresses in Addr1/Addr2, replace them with link addresses
544 // and move to the appropriate container queue
545 NS_ASSERT(selectedBar->GetHeader().GetAddr2() == m_mac->GetAddress());
546 DequeueMpdu(selectedBar);
547 const auto currAddr1 = selectedBar->GetHeader().GetAddr1();
548 auto addr1 =
549 GetWifiRemoteStationManager()->GetAffiliatedStaAddress(currAddr1).value_or(currAddr1);
550 selectedBar->GetHeader().SetAddr1(addr1);
551 selectedBar->GetHeader().SetAddr2(m_self);
552 queue->Enqueue(selectedBar);
553 }
554
555 return selectedBar;
556}
557
558bool
560 Time availableTime,
561 bool initialFrame)
562{
563 NS_LOG_FUNCTION(this << *mpdu << availableTime << initialFrame);
564
565 // First, check if there is a BAR to be transmitted
566 if (!mpdu->GetHeader().IsBlockAckReq())
567 {
568 NS_LOG_DEBUG("Block Ack Manager returned no frame to send");
569 return false;
570 }
571
572 // Prepare the TX parameters. Note that the default ack manager expects the
573 // data TxVector in the m_txVector field to compute the BlockAck TxVector.
574 // The m_txVector field of the TX parameters is set to the BlockAckReq TxVector
575 // a few lines below.
576 WifiTxParameters txParams;
577 txParams.m_txVector =
579
580 if (!TryAddMpdu(mpdu, txParams, availableTime))
581 {
582 NS_LOG_DEBUG("Not enough time to send the BAR frame returned by the Block Ack Manager");
583 return false;
584 }
585
586 // we can transmit the BlockAckReq frame
587 SendPsduWithProtection(GetWifiPsdu(mpdu, txParams.m_txVector), txParams);
588 return true;
589}
590
591bool
593 Time availableTime,
594 bool initialFrame)
595{
596 NS_ASSERT(peekedItem && peekedItem->GetHeader().IsQosData() &&
597 !peekedItem->GetHeader().GetAddr1().IsBroadcast() && !peekedItem->IsFragment());
598 NS_LOG_FUNCTION(this << *peekedItem << availableTime << initialFrame);
599
600 Ptr<QosTxop> edca = m_mac->GetQosTxop(peekedItem->GetHeader().GetQosTid());
601 WifiTxParameters txParams;
602 txParams.m_txVector =
604 Ptr<WifiMpdu> mpdu =
605 edca->GetNextMpdu(m_linkId, peekedItem, txParams, availableTime, initialFrame);
606
607 if (!mpdu)
608 {
609 NS_LOG_DEBUG("Not enough time to transmit a frame");
610 return false;
611 }
612
613 // try A-MPDU aggregation
614 std::vector<Ptr<WifiMpdu>> mpduList =
615 m_mpduAggregator->GetNextAmpdu(mpdu, txParams, availableTime);
616 NS_ASSERT(txParams.m_acknowledgment);
617
618 if (mpduList.size() > 1)
619 {
620 // A-MPDU aggregation succeeded
621 SendPsduWithProtection(Create<WifiPsdu>(std::move(mpduList)), txParams);
622 }
623 else if (txParams.m_acknowledgment->method == WifiAcknowledgment::BAR_BLOCK_ACK)
624 {
625 // a QoS data frame using the Block Ack policy can be followed by a BlockAckReq
626 // frame and a BlockAck frame. Such a sequence is handled by the HT FEM
627 SendPsduWithProtection(Create<WifiPsdu>(mpdu, false), txParams);
628 }
629 else
630 {
631 // transmission can be handled by the base FEM
632 SendMpduWithProtection(mpdu, txParams);
633 }
634
635 return true;
636}
637
638void
640{
641 NS_LOG_FUNCTION(this << acknowledgment);
642 NS_ASSERT(acknowledgment);
643
644 if (acknowledgment->method == WifiAcknowledgment::BLOCK_ACK)
645 {
646 auto blockAcknowledgment = static_cast<WifiBlockAck*>(acknowledgment);
647 Time baTxDuration = m_phy->CalculateTxDuration(GetBlockAckSize(blockAcknowledgment->baType),
648 blockAcknowledgment->blockAckTxVector,
649 m_phy->GetPhyBand());
650 blockAcknowledgment->acknowledgmentTime = m_phy->GetSifs() + baTxDuration;
651 }
652 else if (acknowledgment->method == WifiAcknowledgment::BAR_BLOCK_ACK)
653 {
654 auto barBlockAcknowledgment = static_cast<WifiBarBlockAck*>(acknowledgment);
655 Time barTxDuration =
656 m_phy->CalculateTxDuration(GetBlockAckRequestSize(barBlockAcknowledgment->barType),
657 barBlockAcknowledgment->blockAckReqTxVector,
658 m_phy->GetPhyBand());
659 Time baTxDuration =
660 m_phy->CalculateTxDuration(GetBlockAckSize(barBlockAcknowledgment->baType),
661 barBlockAcknowledgment->blockAckTxVector,
662 m_phy->GetPhyBand());
663 barBlockAcknowledgment->acknowledgmentTime =
664 2 * m_phy->GetSifs() + barTxDuration + baTxDuration;
665 }
666 else
667 {
669 }
670}
671
672void
674{
675 ForwardPsduDown(GetWifiPsdu(mpdu, txVector), txVector);
676}
677
680{
681 return Create<WifiPsdu>(mpdu, false);
682}
683
684void
686{
687 NS_LOG_FUNCTION(this << *mpdu);
688
689 if (mpdu->GetHeader().IsQosData())
690 {
691 uint8_t tid = mpdu->GetHeader().GetQosTid();
692 Ptr<QosTxop> edca = m_mac->GetQosTxop(tid);
693
694 if (m_mac->GetBaAgreementEstablishedAsOriginator(mpdu->GetHeader().GetAddr1(), tid))
695 {
696 // notify the BA manager that the MPDU was acknowledged
697 edca->GetBaManager()->NotifyGotAck(m_linkId, mpdu);
698 }
699 }
700 else if (mpdu->GetHeader().IsAction())
701 {
702 auto addr1 = mpdu->GetHeader().GetAddr1();
703 auto address = GetWifiRemoteStationManager()->GetMldAddress(addr1).value_or(addr1);
704 WifiActionHeader actionHdr;
705 Ptr<Packet> p = mpdu->GetPacket()->Copy();
706 p->RemoveHeader(actionHdr);
707 if (actionHdr.GetCategory() == WifiActionHeader::BLOCK_ACK)
708 {
710 {
711 MgtDelBaHeader delBa;
712 p->PeekHeader(delBa);
713 auto tid = delBa.GetTid();
714 if (delBa.IsByOriginator())
715 {
716 GetBaManager(tid)->DestroyOriginatorAgreement(address, tid);
717 }
718 else
719 {
720 GetBaManager(tid)->DestroyRecipientAgreement(address, tid);
721 }
722 }
724 {
725 // Setup ADDBA response timeout
727 p->PeekHeader(addBa);
728 Ptr<QosTxop> edca = m_mac->GetQosTxop(addBa.GetTid());
729 Simulator::Schedule(edca->GetAddBaResponseTimeout(),
731 edca,
732 address,
733 addBa.GetTid());
734 }
736 {
737 // A recipient Block Ack agreement must exist
739 p->PeekHeader(addBa);
740 auto tid = addBa.GetTid();
741 NS_ASSERT_MSG(GetBaManager(tid)->GetAgreementAsRecipient(address, tid),
742 "Recipient BA agreement {" << address << ", " << +tid
743 << "} not found");
744 m_pendingAddBaResp.erase({address, tid});
745 }
746 }
747 }
749}
750
751void
753{
754 NS_LOG_DEBUG(this);
755
757 {
758 // A TXOP limit of 0 indicates that the TXOP holder may transmit or cause to
759 // be transmitted (as responses) the following within the current TXOP:
760 // f) Any number of BlockAckReq frames
761 // (Sec. 10.22.2.8 of 802.11-2016)
762 NS_LOG_DEBUG("Schedule a transmission from Block Ack Manager in a SIFS");
765
766 // TXOP limit is null, hence the txopDuration parameter is unused
768 }
769 else
770 {
772 }
773}
774
775void
777{
778 NS_LOG_FUNCTION(this << *mpdu);
779
780 if (mpdu->GetHeader().IsQosData())
781 {
782 GetBaManager(mpdu->GetHeader().GetQosTid())->NotifyDiscardedMpdu(mpdu);
783 }
784 else if (mpdu->GetHeader().IsAction())
785 {
786 WifiActionHeader actionHdr;
787 mpdu->GetPacket()->PeekHeader(actionHdr);
788 if (actionHdr.GetCategory() == WifiActionHeader::BLOCK_ACK &&
790 {
791 uint8_t tid = GetTid(mpdu->GetPacket(), mpdu->GetHeader());
792 auto recipient = mpdu->GetHeader().GetAddr1();
793 // if the recipient is an MLD, use its MLD address
794 if (auto mldAddr = GetWifiRemoteStationManager()->GetMldAddress(recipient))
795 {
796 recipient = *mldAddr;
797 }
798 if (auto agreement = GetBaManager(tid)->GetAgreementAsOriginator(recipient, tid);
799 agreement && agreement->get().IsPending())
800 {
801 NS_LOG_DEBUG("No ACK after ADDBA request");
802 Ptr<QosTxop> qosTxop = m_mac->GetQosTxop(tid);
803 qosTxop->NotifyOriginatorAgreementNoReply(recipient, tid);
804 Simulator::Schedule(qosTxop->GetFailedAddBaTimeout(),
806 qosTxop,
807 recipient,
808 tid);
809 }
810 }
811 }
813}
814
815void
817{
818 NS_LOG_FUNCTION(this << *mpdu);
819
820 if (mpdu->GetHeader().IsQosData())
821 {
822 uint8_t tid = mpdu->GetHeader().GetQosTid();
823 Ptr<QosTxop> edca = m_mac->GetQosTxop(tid);
824
825 if (m_mac->GetBaAgreementEstablishedAsOriginator(mpdu->GetHeader().GetAddr1(), tid))
826 {
827 // notify the BA manager that the MPDU was not acknowledged
828 edca->GetBaManager()->NotifyMissedAck(m_linkId, mpdu);
829 return;
830 }
831 }
833}
834
835void
837{
838 NS_LOG_FUNCTION(this << *psdu);
839
840 auto tids = psdu->GetTids();
841
842 if (tids.empty() || // no QoS data frames included
843 !m_mac->GetBaAgreementEstablishedAsOriginator(psdu->GetAddr1(), *tids.begin()))
844 {
846 return;
847 }
848
849 // iterate over MPDUs in reverse order (to process them in decreasing order of sequence number)
850 auto mpduIt = psdu->end();
851
852 do
853 {
854 std::advance(mpduIt, -1);
855
856 const WifiMacHeader& hdr = (*mpduIt)->GetOriginal()->GetHeader();
857 if (hdr.IsQosData())
858 {
859 uint8_t tid = hdr.GetQosTid();
861
862 if (!hdr.IsRetry() && !(*mpduIt)->IsInFlight())
863 {
864 // The MPDU has never been transmitted, so we can make its sequence
865 // number available again if it is the highest sequence number
866 // assigned by the MAC TX middle
867 uint16_t currentNextSeq = m_txMiddle->PeekNextSequenceNumberFor(&hdr);
868
869 if ((hdr.GetSequenceNumber() + 1) % SEQNO_SPACE_SIZE == currentNextSeq)
870 {
871 (*mpduIt)->UnassignSeqNo();
872 m_txMiddle->SetSequenceNumberFor(&hdr);
873
874 NS_LOG_DEBUG("Released " << hdr.GetSequenceNumber()
875 << ", next sequence "
876 "number for dest="
877 << hdr.GetAddr1() << ",tid=" << +tid << " is "
878 << m_txMiddle->PeekNextSequenceNumberFor(&hdr));
879 }
880 }
881 }
882 } while (mpduIt != psdu->begin());
883}
884
885Time
887{
888 NS_LOG_FUNCTION(this << txDuration << &txParams);
889
891
893 {
894 NS_ASSERT(txParams.m_acknowledgment &&
895 txParams.m_acknowledgment->acknowledgmentTime != Time::Min());
896 return txParams.m_acknowledgment->acknowledgmentTime;
897 }
898
899 // under multiple protection settings, if the TXOP limit is not null, Duration/ID
900 // is set to cover the remaining TXOP time (Sec. 9.2.5.2 of 802.11-2016).
901 // The TXOP holder may exceed the TXOP limit in some situations (Sec. 10.22.2.8
902 // of 802.11-2016)
903 return std::max(m_edca->GetRemainingTxop(m_linkId) - txDuration, Seconds(0));
904}
905
906void
908{
909 NS_LOG_FUNCTION(this << psdu << &txParams);
910
911 m_psdu = psdu;
912 m_txParams = std::move(txParams);
913
914#ifdef NS3_BUILD_PROFILE_DEBUG
915 // If protection is required, the MPDUs must be stored in some queue because
916 // they are not put back in a queue if the RTS/CTS exchange fails
918 {
919 for (const auto& mpdu : *PeekPointer(m_psdu))
920 {
921 NS_ASSERT(mpdu->GetHeader().IsCtl() || mpdu->IsQueued());
922 }
923 }
924#endif
925
926 // Make sure that the acknowledgment time has been computed, so that SendRts()
927 // and SendCtsToSelf() can reuse this value.
929
930 if (m_txParams.m_acknowledgment->acknowledgmentTime == Time::Min())
931 {
933 }
934
935 // Set QoS Ack policy
937
938 for (const auto& mpdu : *PeekPointer(m_psdu))
939 {
940 if (mpdu->IsQueued())
941 {
942 mpdu->SetInFlight(m_linkId);
943 }
944 }
945
947}
948
949void
951{
952 NS_LOG_FUNCTION(this);
953 if (m_psdu)
954 {
956 m_sentRtsTo.clear();
957 SendPsdu();
958 return;
959 }
961}
962
963void
965{
966 NS_LOG_FUNCTION(this << *rts << txVector);
967
968 if (!m_psdu)
969 {
970 // A CTS Timeout occurred when protecting a single MPDU is handled by the
971 // parent classes
973 return;
974 }
975
977 m_psdu = nullptr;
978}
979
980void
982{
983 NS_LOG_FUNCTION(this);
984
985 Time txDuration =
987
989
991 {
993
994 std::set<uint8_t> tids = m_psdu->GetTids();
995 NS_ASSERT_MSG(tids.size() <= 1, "Multi-TID A-MPDUs are not supported");
996
997 if (tids.empty() || m_psdu->GetAckPolicyForTid(*tids.begin()) == WifiMacHeader::NO_ACK)
998 {
999 // No acknowledgment, hence dequeue the PSDU if it is stored in a queue
1001 }
1002 }
1004 {
1006
1007 // the timeout duration is "aSIFSTime + aSlotTime + aRxPHYStartDelay, starting
1008 // at the PHY-TXEND.confirm primitive" (section 10.3.2.9 or 10.22.2.2 of 802.11-2016).
1009 // aRxPHYStartDelay equals the time to transmit the PHY header.
1010 auto blockAcknowledgment = static_cast<WifiBlockAck*>(m_txParams.m_acknowledgment.get());
1011
1012 Time timeout =
1013 txDuration + m_phy->GetSifs() + m_phy->GetSlot() +
1014 m_phy->CalculatePhyPreambleAndHeaderDuration(blockAcknowledgment->blockAckTxVector);
1017 timeout,
1018 {m_psdu->GetAddr1()},
1020 this,
1021 m_psdu,
1024 }
1026 {
1028
1029 // schedule the transmission of a BAR in a SIFS
1030 std::set<uint8_t> tids = m_psdu->GetTids();
1031 NS_ABORT_MSG_IF(tids.size() > 1,
1032 "Acknowledgment method incompatible with a Multi-TID A-MPDU");
1033 uint8_t tid = *tids.begin();
1034
1035 Ptr<QosTxop> edca = m_mac->GetQosTxop(tid);
1036 auto [reqHdr, hdr] = edca->PrepareBlockAckRequest(m_psdu->GetAddr1(), tid);
1037 GetBaManager(tid)->ScheduleBar(reqHdr, hdr);
1038
1040 }
1041 else
1042 {
1043 NS_ABORT_MSG("Unable to handle the selected acknowledgment method ("
1044 << m_txParams.m_acknowledgment.get() << ")");
1045 }
1046
1047 // transmit the PSDU
1048 if (m_psdu->GetNMpdus() > 1)
1049 {
1051 }
1052 else
1053 {
1055 }
1056
1058 {
1059 // we are done in case the A-MPDU does not require acknowledgment
1060 m_psdu = nullptr;
1061 }
1062}
1063
1064void
1066{
1067 NS_LOG_FUNCTION(this << psdu);
1068
1069 for (const auto& mpdu : *PeekPointer(psdu))
1070 {
1071 auto& hdr = mpdu->GetHeader();
1072
1073 if (hdr.IsQosData() && hdr.HasData())
1074 {
1075 auto tid = hdr.GetQosTid();
1076 m_mac->GetQosTxop(tid)->CompleteMpduTx(mpdu);
1077 }
1078 }
1079}
1080
1081void
1083{
1084 NS_LOG_FUNCTION(this << psdu);
1085
1086 // use an array to avoid computing the queue size for every MPDU in the PSDU
1087 std::array<std::optional<uint8_t>, 8> queueSizeForTid;
1088
1089 for (const auto& mpdu : *PeekPointer(psdu))
1090 {
1091 WifiMacHeader& hdr = mpdu->GetHeader();
1092
1093 if (hdr.IsQosData())
1094 {
1095 uint8_t tid = hdr.GetQosTid();
1096 auto edca = m_mac->GetQosTxop(tid);
1097
1098 if (m_mac->GetTypeOfStation() == STA && (m_setQosQueueSize || hdr.IsQosEosp()))
1099 {
1100 // set the Queue Size subfield of the QoS Control field
1101 if (!queueSizeForTid[tid].has_value())
1102 {
1103 queueSizeForTid[tid] = edca->GetQosQueueSize(tid, hdr.GetAddr1());
1104 }
1105
1106 hdr.SetQosEosp();
1107 hdr.SetQosQueueSize(queueSizeForTid[tid].value());
1108 }
1109 }
1110 }
1111
1113}
1114
1115void
1117{
1118 NS_LOG_DEBUG(this << psdu);
1119
1120 for (const auto& mpdu : *PeekPointer(psdu))
1121 {
1122 DequeueMpdu(mpdu);
1123 }
1124}
1125
1126void
1128{
1129 NS_LOG_FUNCTION(this << psdu << txVector);
1130
1131 NS_LOG_DEBUG("Transmitting a PSDU: " << *psdu << " TXVECTOR: " << txVector);
1132 FinalizeMacHeader(psdu);
1133 NotifyTxToEdca(psdu);
1134 m_allowedWidth = std::min(m_allowedWidth, txVector.GetChannelWidth());
1135
1136 if (psdu->IsAggregate())
1137 {
1138 txVector.SetAggregation(true);
1139 }
1140
1141 m_phy->Send(psdu, txVector);
1142}
1143
1144bool
1146 const WifiTxParameters& txParams,
1147 Time ppduDurationLimit) const
1148{
1149 NS_ASSERT(mpdu);
1150 NS_LOG_FUNCTION(this << *mpdu << &txParams << ppduDurationLimit);
1151
1152 Mac48Address receiver = mpdu->GetHeader().GetAddr1();
1153 uint32_t ampduSize = txParams.GetSizeIfAddMpdu(mpdu);
1154
1155 if (txParams.GetSize(receiver) > 0)
1156 {
1157 // we are attempting to perform A-MPDU aggregation, hence we have to check
1158 // that we meet the limit on the max A-MPDU size
1159 uint8_t tid;
1160 const WifiTxParameters::PsduInfo* info;
1161
1162 if (mpdu->GetHeader().IsQosData())
1163 {
1164 tid = mpdu->GetHeader().GetQosTid();
1165 }
1166 else if ((info = txParams.GetPsduInfo(receiver)) && !info->seqNumbers.empty())
1167 {
1168 tid = info->seqNumbers.begin()->first;
1169 }
1170 else
1171 {
1172 NS_ABORT_MSG("Cannot aggregate a non-QoS data frame to an A-MPDU that does"
1173 " not contain any QoS data frame");
1174 }
1175
1176 WifiModulationClass modulation = txParams.m_txVector.GetModulationClass();
1177
1178 if (!IsWithinAmpduSizeLimit(ampduSize, receiver, tid, modulation))
1179 {
1180 return false;
1181 }
1182 }
1183
1184 return IsWithinSizeAndTimeLimits(ampduSize, receiver, txParams, ppduDurationLimit);
1185}
1186
1187bool
1189 Mac48Address receiver,
1190 uint8_t tid,
1191 WifiModulationClass modulation) const
1192{
1193 NS_LOG_FUNCTION(this << ampduSize << receiver << +tid << modulation);
1194
1195 uint32_t maxAmpduSize = m_mpduAggregator->GetMaxAmpduSize(receiver, tid, modulation);
1196
1197 if (maxAmpduSize == 0)
1198 {
1199 NS_LOG_DEBUG("A-MPDU aggregation disabled");
1200 return false;
1201 }
1202
1203 if (ampduSize > maxAmpduSize)
1204 {
1205 NS_LOG_DEBUG("the frame does not meet the constraint on max A-MPDU size (" << maxAmpduSize
1206 << ")");
1207 return false;
1208 }
1209 return true;
1210}
1211
1212bool
1214 WifiTxParameters& txParams,
1215 Time availableTime) const
1216{
1217 NS_ASSERT(msdu && msdu->GetHeader().IsQosData());
1218 NS_LOG_FUNCTION(this << *msdu << &txParams << availableTime);
1219
1220 // check if aggregating the given MSDU requires a different protection method
1221 NS_ASSERT(txParams.m_protection);
1222 Time protectionTime = txParams.m_protection->protectionTime;
1223
1224 std::unique_ptr<WifiProtection> protection;
1225 protection = GetProtectionManager()->TryAggregateMsdu(msdu, txParams);
1226 bool protectionSwapped = false;
1227
1228 if (protection)
1229 {
1230 // the protection method has changed, calculate the new protection time
1231 CalculateProtectionTime(protection.get());
1232 protectionTime = protection->protectionTime;
1233 // swap unique pointers, so that the txParams that is passed to the next
1234 // call to IsWithinLimitsIfAggregateMsdu is the most updated one
1235 txParams.m_protection.swap(protection);
1236 protectionSwapped = true;
1237 }
1238 NS_ASSERT(protectionTime != Time::Min());
1239
1240 // check if aggregating the given MSDU requires a different acknowledgment method
1241 NS_ASSERT(txParams.m_acknowledgment);
1242 Time acknowledgmentTime = txParams.m_acknowledgment->acknowledgmentTime;
1243
1244 std::unique_ptr<WifiAcknowledgment> acknowledgment;
1245 acknowledgment = GetAckManager()->TryAggregateMsdu(msdu, txParams);
1246 bool acknowledgmentSwapped = false;
1247
1248 if (acknowledgment)
1249 {
1250 // the acknowledgment method has changed, calculate the new acknowledgment time
1251 CalculateAcknowledgmentTime(acknowledgment.get());
1252 acknowledgmentTime = acknowledgment->acknowledgmentTime;
1253 // swap unique pointers, so that the txParams that is passed to the next
1254 // call to IsWithinLimitsIfAggregateMsdu is the most updated one
1255 txParams.m_acknowledgment.swap(acknowledgment);
1256 acknowledgmentSwapped = true;
1257 }
1258 NS_ASSERT(acknowledgmentTime != Time::Min());
1259
1260 Time ppduDurationLimit = Time::Min();
1261 if (availableTime != Time::Min())
1262 {
1263 ppduDurationLimit = availableTime - protectionTime - acknowledgmentTime;
1264 }
1265
1266 if (!IsWithinLimitsIfAggregateMsdu(msdu, txParams, ppduDurationLimit))
1267 {
1268 // adding MPDU failed, restore protection and acknowledgment methods
1269 // if they were swapped
1270 if (protectionSwapped)
1271 {
1272 txParams.m_protection.swap(protection);
1273 }
1274 if (acknowledgmentSwapped)
1275 {
1276 txParams.m_acknowledgment.swap(acknowledgment);
1277 }
1278 return false;
1279 }
1280
1281 // the given MPDU can be added, hence update the txParams
1282 txParams.AggregateMsdu(msdu);
1283 UpdateTxDuration(msdu->GetHeader().GetAddr1(), txParams);
1284
1285 return true;
1286}
1287
1288bool
1290 const WifiTxParameters& txParams,
1291 Time ppduDurationLimit) const
1292{
1293 NS_ASSERT(msdu && msdu->GetHeader().IsQosData());
1294 NS_LOG_FUNCTION(this << *msdu << &txParams << ppduDurationLimit);
1295
1296 std::pair<uint16_t, uint32_t> ret = txParams.GetSizeIfAggregateMsdu(msdu);
1297 Mac48Address receiver = msdu->GetHeader().GetAddr1();
1298 uint8_t tid = msdu->GetHeader().GetQosTid();
1299 WifiModulationClass modulation = txParams.m_txVector.GetModulationClass();
1300
1301 // Check that the limit on A-MSDU size is met
1302 uint16_t maxAmsduSize = m_msduAggregator->GetMaxAmsduSize(receiver, tid, modulation);
1303
1304 if (maxAmsduSize == 0)
1305 {
1306 NS_LOG_DEBUG("A-MSDU aggregation disabled");
1307 return false;
1308 }
1309
1310 if (ret.first > maxAmsduSize)
1311 {
1312 NS_LOG_DEBUG("No other MSDU can be aggregated: maximum A-MSDU size (" << maxAmsduSize
1313 << ") reached ");
1314 return false;
1315 }
1316
1317 const WifiTxParameters::PsduInfo* info = txParams.GetPsduInfo(msdu->GetHeader().GetAddr1());
1318 NS_ASSERT(info);
1319
1320 if (info->ampduSize > 0)
1321 {
1322 // the A-MSDU being built is aggregated to other MPDUs in an A-MPDU.
1323 // Check that the limit on A-MPDU size is met.
1324 if (!IsWithinAmpduSizeLimit(ret.second, receiver, tid, modulation))
1325 {
1326 return false;
1327 }
1328 }
1329
1330 return IsWithinSizeAndTimeLimits(ret.second, receiver, txParams, ppduDurationLimit);
1331}
1332
1333void
1335{
1336 NS_LOG_FUNCTION(this << *psdu << txVector);
1337
1339
1340 bool resetCw;
1341 MissedBlockAck(psdu, txVector, resetCw);
1342
1344
1345 if (resetCw)
1346 {
1348 }
1349 else
1350 {
1352 }
1353
1354 m_psdu = nullptr;
1356}
1357
1358void
1360 const WifiTxVector& txVector,
1361 bool& resetCw)
1362{
1363 NS_LOG_FUNCTION(this << psdu << txVector << resetCw);
1364
1365 auto recipient = psdu->GetAddr1();
1366 auto recipientMld = GetWifiRemoteStationManager()->GetMldAddress(recipient).value_or(recipient);
1367 bool isBar;
1368 uint8_t tid;
1369
1370 if (psdu->GetNMpdus() == 1 && psdu->GetHeader(0).IsBlockAckReq())
1371 {
1372 isBar = true;
1373 CtrlBAckRequestHeader baReqHdr;
1374 psdu->GetPayload(0)->PeekHeader(baReqHdr);
1375 tid = baReqHdr.GetTidInfo();
1376 }
1377 else
1378 {
1379 isBar = false;
1381 ->ReportAmpduTxStatus(recipient, 0, psdu->GetNMpdus(), 0, 0, txVector);
1382 std::set<uint8_t> tids = psdu->GetTids();
1383 NS_ABORT_MSG_IF(tids.size() > 1, "Multi-TID A-MPDUs not handled here");
1384 NS_ASSERT(!tids.empty());
1385 tid = *tids.begin();
1386 }
1387
1388 Ptr<QosTxop> edca = m_mac->GetQosTxop(tid);
1389
1390 if (edca->UseExplicitBarAfterMissedBlockAck() || isBar)
1391 {
1392 // we have to send a BlockAckReq, if needed
1393 if (GetBaManager(tid)->NeedBarRetransmission(tid, recipientMld))
1394 {
1395 NS_LOG_DEBUG("Missed Block Ack, transmit a BlockAckReq");
1406 if (isBar)
1407 {
1408 psdu->GetHeader(0).SetRetry();
1409 }
1410 else
1411 {
1412 // missed block ack after data frame with Implicit BAR Ack policy
1413 auto [reqHdr, hdr] = edca->PrepareBlockAckRequest(recipient, tid);
1414 GetBaManager(tid)->ScheduleBar(reqHdr, hdr);
1415 }
1416 resetCw = false;
1417 }
1418 else
1419 {
1420 NS_LOG_DEBUG("Missed Block Ack, do not transmit a BlockAckReq");
1421 // if a BA agreement exists, we can get here if there is no outstanding
1422 // MPDU whose lifetime has not expired yet.
1424 if (isBar)
1425 {
1426 DequeuePsdu(psdu);
1427 }
1428 if (m_mac->GetBaAgreementEstablishedAsOriginator(recipient, tid))
1429 {
1430 // schedule a BlockAckRequest to be sent only if there are data frames queued
1431 // for this recipient
1432 GetBaManager(tid)->AddToSendBarIfDataQueuedList(recipientMld, tid);
1433 }
1434 resetCw = true;
1435 }
1436 }
1437 else
1438 {
1439 // we have to retransmit the data frames, if needed
1440 if (!GetWifiRemoteStationManager()->NeedRetransmission(*psdu->begin()))
1441 {
1442 NS_LOG_DEBUG("Missed Block Ack, do not retransmit the data frames");
1444 for (const auto& mpdu : *PeekPointer(psdu))
1445 {
1447 DequeueMpdu(mpdu);
1448 }
1449 resetCw = true;
1450 }
1451 else
1452 {
1453 NS_LOG_DEBUG("Missed Block Ack, retransmit data frames");
1454 GetBaManager(tid)->NotifyMissedBlockAck(m_linkId, recipientMld, tid);
1455 resetCw = false;
1456 }
1457 }
1458}
1459
1460void
1462 Time durationId,
1463 WifiTxVector& blockAckTxVector,
1464 double rxSnr)
1465{
1466 NS_LOG_FUNCTION(this << durationId << blockAckTxVector << rxSnr);
1467
1468 WifiMacHeader hdr;
1470 auto addr1 = agreement.GetPeer();
1471 if (auto originator = GetWifiRemoteStationManager()->GetAffiliatedStaAddress(addr1))
1472 {
1473 addr1 = *originator;
1474 }
1475 hdr.SetAddr1(addr1);
1476 hdr.SetAddr2(m_self);
1477 hdr.SetDsNotFrom();
1478 hdr.SetDsNotTo();
1479
1480 CtrlBAckResponseHeader blockAck;
1481 blockAck.SetType(agreement.GetBlockAckType());
1482 blockAck.SetTidInfo(agreement.GetTid());
1483 agreement.FillBlockAckBitmap(&blockAck);
1484
1485 Ptr<Packet> packet = Create<Packet>();
1486 packet->AddHeader(blockAck);
1487 Ptr<WifiPsdu> psdu = GetWifiPsdu(Create<WifiMpdu>(packet, hdr), blockAckTxVector);
1488
1489 // 802.11-2016, Section 9.2.5.7: In a BlockAck frame transmitted in response
1490 // to a BlockAckReq frame or transmitted in response to a frame containing an
1491 // implicit block ack request, the Duration/ID field is set to the value obtained
1492 // from the Duration/ ID field of the frame that elicited the response minus the
1493 // time, in microseconds between the end of the PPDU carrying the frame that
1494 // elicited the response and the end of the PPDU carrying the BlockAck frame.
1495 Time baDurationId = durationId - m_phy->GetSifs() -
1496 m_phy->CalculateTxDuration(psdu, blockAckTxVector, m_phy->GetPhyBand());
1497 // The TXOP holder may exceed the TXOP limit in some situations (Sec. 10.22.2.8 of 802.11-2016)
1498 if (baDurationId.IsStrictlyNegative())
1499 {
1500 baDurationId = Seconds(0);
1501 }
1502 psdu->GetHeader(0).SetDuration(baDurationId);
1503
1504 SnrTag tag;
1505 tag.Set(rxSnr);
1506 psdu->GetPayload(0)->AddPacketTag(tag);
1507
1508 ForwardPsduDown(psdu, blockAckTxVector);
1509}
1510
1511void
1513 RxSignalInfo rxSignalInfo,
1514 const WifiTxVector& txVector,
1515 bool inAmpdu)
1516{
1517 // The received MPDU is either broadcast or addressed to this station
1518 NS_ASSERT(mpdu->GetHeader().GetAddr1().IsGroup() || mpdu->GetHeader().GetAddr1() == m_self);
1519
1520 double rxSnr = rxSignalInfo.snr;
1521 const WifiMacHeader& hdr = mpdu->GetHeader();
1522
1523 if (hdr.IsCtl())
1524 {
1525 if (hdr.IsCts() && m_txTimer.IsRunning() &&
1527 {
1528 NS_ABORT_MSG_IF(inAmpdu, "Received CTS as part of an A-MPDU");
1529 NS_ASSERT(hdr.GetAddr1() == m_self);
1530
1531 Mac48Address sender = m_psdu->GetAddr1();
1532 NS_LOG_DEBUG("Received CTS from=" << sender);
1533
1534 SnrTag tag;
1535 mpdu->GetPacket()->PeekPacketTag(tag);
1536 GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
1538 rxSnr,
1539 txVector.GetMode(),
1540 tag.Get());
1541
1542 m_txTimer.Cancel();
1546 this);
1547 }
1548 else if (hdr.IsBlockAck() && m_txTimer.IsRunning() &&
1550 {
1551 Mac48Address sender = hdr.GetAddr2();
1552 NS_LOG_DEBUG("Received BlockAck from=" << sender);
1553
1554 SnrTag tag;
1555 mpdu->GetPacket()->PeekPacketTag(tag);
1556
1557 // notify the Block Ack Manager
1558 CtrlBAckResponseHeader blockAck;
1559 mpdu->GetPacket()->PeekHeader(blockAck);
1560 uint8_t tid = blockAck.GetTidInfo();
1561 std::pair<uint16_t, uint16_t> ret =
1562 GetBaManager(tid)->NotifyGotBlockAck(m_linkId,
1563 blockAck,
1564 m_mac->GetMldAddress(sender).value_or(sender),
1565 {tid});
1567 ret.first,
1568 ret.second,
1569 rxSnr,
1570 tag.Get(),
1572
1573 // cancel the timer
1574 m_txTimer.Cancel();
1576
1577 // Reset the CW
1579
1580 // if this BlockAck was sent in response to a BlockAckReq, dequeue the blockAckReq
1581 if (m_psdu && m_psdu->GetNMpdus() == 1 && m_psdu->GetHeader(0).IsBlockAckReq())
1582 {
1584 }
1585 m_psdu = nullptr;
1587 }
1588 else if (hdr.IsBlockAckReq())
1589 {
1590 NS_ASSERT(hdr.GetAddr1() == m_self);
1591 NS_ABORT_MSG_IF(inAmpdu, "BlockAckReq in A-MPDU is not supported");
1592
1593 Mac48Address sender = hdr.GetAddr2();
1594 NS_LOG_DEBUG("Received BlockAckReq from=" << sender);
1595
1596 CtrlBAckRequestHeader blockAckReq;
1597 mpdu->GetPacket()->PeekHeader(blockAckReq);
1598 NS_ABORT_MSG_IF(blockAckReq.IsMultiTid(), "Multi-TID BlockAckReq not supported");
1599 uint8_t tid = blockAckReq.GetTidInfo();
1600
1601 auto agreement = m_mac->GetBaAgreementEstablishedAsRecipient(sender, tid);
1602
1603 if (!agreement)
1604 {
1605 NS_LOG_DEBUG("There's not a valid agreement for this BlockAckReq");
1606 return;
1607 }
1608
1609 GetBaManager(tid)->NotifyGotBlockAckRequest(
1610 m_mac->GetMldAddress(sender).value_or(sender),
1611 tid,
1612 blockAckReq.GetStartingSequence());
1613
1614 NS_LOG_DEBUG("Schedule Block Ack");
1616 m_phy->GetSifs(),
1618 this,
1619 *agreement,
1620 hdr.GetDuration(),
1621 GetWifiRemoteStationManager()->GetBlockAckTxVector(sender, txVector),
1622 rxSnr);
1623 }
1624 else
1625 {
1626 // the received control frame cannot be handled here
1627 QosFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
1628 }
1629 return;
1630 }
1631
1632 if (hdr.IsQosData() && hdr.HasData() && hdr.GetAddr1() == m_self)
1633 {
1634 uint8_t tid = hdr.GetQosTid();
1635
1637 {
1638 // a Block Ack agreement has been established
1639 NS_LOG_DEBUG("Received from=" << hdr.GetAddr2() << " (" << *mpdu << ")");
1640
1641 GetBaManager(tid)->NotifyGotMpdu(mpdu);
1642
1643 if (!inAmpdu && hdr.GetQosAckPolicy() == WifiMacHeader::NORMAL_ACK)
1644 {
1645 NS_LOG_DEBUG("Schedule Normal Ack");
1648 this,
1649 hdr,
1650 txVector,
1651 rxSnr);
1652 }
1653 return;
1654 }
1655 // We let the QosFrameExchangeManager handle QoS data frame not belonging
1656 // to a Block Ack agreement
1657 }
1658
1659 QosFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
1660}
1661
1662void
1664 const RxSignalInfo& rxSignalInfo,
1665 const WifiTxVector& txVector,
1666 const std::vector<bool>& perMpduStatus)
1667{
1668 std::set<uint8_t> tids = psdu->GetTids();
1669
1670 // Multi-TID A-MPDUs are not supported yet
1671 if (tids.size() == 1)
1672 {
1673 uint8_t tid = *tids.begin();
1674 WifiMacHeader::QosAckPolicy ackPolicy = psdu->GetAckPolicyForTid(tid);
1675 NS_ASSERT(psdu->GetNMpdus() > 1);
1676
1677 if (ackPolicy == WifiMacHeader::NORMAL_ACK)
1678 {
1679 // Normal Ack or Implicit Block Ack Request
1680 NS_LOG_DEBUG("Schedule Block Ack");
1681 auto agreement = m_mac->GetBaAgreementEstablishedAsRecipient(psdu->GetAddr2(), tid);
1682 NS_ASSERT(agreement);
1683
1685 m_phy->GetSifs(),
1687 this,
1688 *agreement,
1689 psdu->GetDuration(),
1690 GetWifiRemoteStationManager()->GetBlockAckTxVector(psdu->GetAddr2(), txVector),
1691 rxSignalInfo.snr);
1692 }
1693 }
1694}
1695
1696} // 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.
std::set< Mac48Address > m_sentRtsTo
the STA(s) which we sent an RTS to (waiting for CTS)
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
virtual void StartProtection(const WifiTxParameters &txParams)
Start the protection mechanism indicated by the given TX parameters.
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
std::set< Mac48Address > m_protectedStas
STAs that have replied to an RTS in this TXOP.
virtual void RetransmitMpduAfterMissedAck(Ptr< WifiMpdu > mpdu) const
Retransmit an MPDU that was not acknowledged.
virtual void ProtectionCompleted()
Transmit prepared frame upon successful protection mechanism.
virtual void NotifyReceivedNormalAck(Ptr< WifiMpdu > mpdu)
Notify other components that an MPDU was acknowledged.
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)
virtual void FinalizeMacHeader(Ptr< const WifiPsdu > psdu)
Finalize the MAC header of the MPDUs in the given PSDU before transmission.
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 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 FinalizeMacHeader(Ptr< const WifiPsdu > psdu) override
Finalize the MAC header of the MPDUs in the given PSDU before transmission.
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 ProtectionCompleted() override
Transmit prepared frame upon successful protection mechanism.
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.
bool SendAddBaRequest(Mac48Address recipient, uint8_t tid, uint16_t startingSeq, uint16_t timeout, bool immediateBAck, Time availableTime)
Sends an ADDBA Request to establish a block ack agreement with STA addressed by recipient for TID tid...
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:795
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:926
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:1045
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...
bool TryAddMpdu(Ptr< const WifiMpdu > mpdu, WifiTxParameters &txParams, Time availableTime) const
Recompute the protection and acknowledgment methods to use if the given MPDU is added to the frame be...
void DoDispose() override
Destructor implementation.
Ptr< BlockAckManager > GetBaManager()
Get the Block Ack Manager associated with this QosTxop.
Definition: qos-txop.cc:273
AcIndex GetAccessCategory() const
Get the access category of this object.
Definition: qos-txop.cc:774
void AddBaResponseTimeout(Mac48Address recipient, uint8_t tid)
Callback when ADDBA response is not received after timeout.
Definition: qos-txop.cc:714
virtual Time GetRemainingTxop(uint8_t linkId) const
Return the remaining duration in the current TXOP on the given link.
Definition: qos-txop.cc:599
uint8_t GetQosQueueSize(uint8_t tid, Mac48Address receiver) const
Get the value for the Queue Size subfield of the QoS Control field of a QoS data frame of the given T...
Definition: qos-txop.cc:166
void ResetBa(Mac48Address recipient, uint8_t tid)
Reset BA agreement after BA negotiation failed.
Definition: qos-txop.cc:727
void CompleteMpduTx(Ptr< WifiMpdu > mpdu)
Stores an MPDU (part of an A-MPDU) in block ack agreement (i.e.
Definition: qos-txop.cc:672
std::pair< CtrlBAckRequestHeader, WifiMacHeader > PrepareBlockAckRequest(Mac48Address recipient, uint8_t tid) const
Definition: qos-txop.cc:291
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:558
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:491
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:313
Ptr< WifiMacQueue > GetWifiMacQueue() const
Return the packet queue associated with this Txop.
Definition: txop.cc:231
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:304
virtual void Queue(Ptr< Packet > packet, const WifiMacHeader &hdr)
Definition: txop.cc:524
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:930
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:539
void SetAction(CategoryValue type, ActionValue action)
Set action for this Action header.
Definition: mgt-headers.cc:601
CategoryValue GetCategory() const
Return the category value.
Definition: mgt-headers.cc:658
ActionValue GetAction() const
Return the action value.
Definition: mgt-headers.cc:693
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.
virtual 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:1634
TypeOfStation GetTypeOfStation() const
Return the type of station.
Definition: wifi-mac.cc:427
RecipientAgreementOptConstRef GetBaAgreementEstablishedAsRecipient(Mac48Address originator, uint8_t tid) const
Definition: wifi-mac.cc:1695
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:545
OriginatorAgreementOptConstRef GetBaAgreementEstablishedAsOriginator(Mac48Address recipient, uint8_t tid) const
Definition: wifi-mac.cc:1681
Mac48Address GetAddress() const
Definition: wifi-mac.cc:452
Ptr< QosTxop > GetQosTxop(AcIndex ac) const
Accessor for a specified EDCA object.
Definition: wifi-mac.cc:499
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:1709
Time GetSlot() const
Return the slot duration for this PHY.
Definition: wifi-phy.cc:795
Time GetSifs() const
Return the Short Interframe Space (SIFS) for this PHY.
Definition: wifi-phy.cc:783
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition: wifi-phy.cc:1496
WifiPhyBand GetPhyBand() const
Get the configured Wi-Fi band.
Definition: wifi-phy.cc:1005
static Time CalculatePhyPreambleAndHeaderDuration(const WifiTxVector &txVector)
Definition: wifi-phy.cc:1489
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, const std::set< Mac48Address > &from, 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.
uint16_t GetChannelWidth() const
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:86
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition: abort.h:49
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_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:1349
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1325
uint8_t GetTid(Ptr< const Packet > packet, const WifiMacHeader hdr)
This function is useful to get traffic id of different packet types.
Definition: qos-utils.cc:191
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
@ STA
Definition: wifi-mac.h:65
@ 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:484
std::tuple< WifiContainerQueueType, WifiReceiverAddressType, Mac48Address, std::optional< uint8_t > > WifiContainerQueueId
Tuple (queue type, receiver address type, Address, TID) identifying a container queue.
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
static constexpr uint16_t SEQNO_SPACE_SIZE
Size of the space of sequence numbers.
Definition: wifi-utils.h:185
uint32_t GetBlockAckSize(BlockAckType type)
Return the total BlockAck size (including FCS trailer).
Definition: wifi-utils.cc:66
ns3::Time timeout
RxSignalInfo structure containing info on the received signal.
Definition: phy-entity.h:69
double snr
SNR in linear scale.
Definition: phy-entity.h:70
WifiAcknowledgment is an abstract base struct.
const Method method
acknowledgment method
WifiBarBlockAck specifies that a BlockAckReq is sent to solicit a Block Ack response.
WifiBlockAck specifies that acknowledgment via Block Ack is required.
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:723
BlockAckActionValue blockAck
block ack
Definition: mgt-headers.h:725