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 WifiBlockAck* 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 WifiBarBlockAck* barBlockAcknowledgment = static_cast<WifiBarBlockAck*>(acknowledgment);
655 Time barTxDuration =
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 WifiBlockAck* blockAcknowledgment =
1011 static_cast<WifiBlockAck*>(m_txParams.m_acknowledgment.get());
1012
1013 Time timeout =
1014 txDuration + m_phy->GetSifs() + m_phy->GetSlot() +
1018 timeout,
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
1135 if (psdu->IsAggregate())
1136 {
1137 txVector.SetAggregation(true);
1138 }
1139
1140 m_phy->Send(psdu, txVector);
1141}
1142
1143bool
1145 const WifiTxParameters& txParams,
1146 Time ppduDurationLimit) const
1147{
1148 NS_ASSERT(mpdu);
1149 NS_LOG_FUNCTION(this << *mpdu << &txParams << ppduDurationLimit);
1150
1151 Mac48Address receiver = mpdu->GetHeader().GetAddr1();
1152 uint32_t ampduSize = txParams.GetSizeIfAddMpdu(mpdu);
1153
1154 if (txParams.GetSize(receiver) > 0)
1155 {
1156 // we are attempting to perform A-MPDU aggregation, hence we have to check
1157 // that we meet the limit on the max A-MPDU size
1158 uint8_t tid;
1159 const WifiTxParameters::PsduInfo* info;
1160
1161 if (mpdu->GetHeader().IsQosData())
1162 {
1163 tid = mpdu->GetHeader().GetQosTid();
1164 }
1165 else if ((info = txParams.GetPsduInfo(receiver)) && !info->seqNumbers.empty())
1166 {
1167 tid = info->seqNumbers.begin()->first;
1168 }
1169 else
1170 {
1171 NS_ABORT_MSG("Cannot aggregate a non-QoS data frame to an A-MPDU that does"
1172 " not contain any QoS data frame");
1173 }
1174
1175 WifiModulationClass modulation = txParams.m_txVector.GetModulationClass();
1176
1177 if (!IsWithinAmpduSizeLimit(ampduSize, receiver, tid, modulation))
1178 {
1179 return false;
1180 }
1181 }
1182
1183 return IsWithinSizeAndTimeLimits(ampduSize, receiver, txParams, ppduDurationLimit);
1184}
1185
1186bool
1188 Mac48Address receiver,
1189 uint8_t tid,
1190 WifiModulationClass modulation) const
1191{
1192 NS_LOG_FUNCTION(this << ampduSize << receiver << +tid << modulation);
1193
1194 uint32_t maxAmpduSize = m_mpduAggregator->GetMaxAmpduSize(receiver, tid, modulation);
1195
1196 if (maxAmpduSize == 0)
1197 {
1198 NS_LOG_DEBUG("A-MPDU aggregation disabled");
1199 return false;
1200 }
1201
1202 if (ampduSize > maxAmpduSize)
1203 {
1204 NS_LOG_DEBUG("the frame does not meet the constraint on max A-MPDU size (" << maxAmpduSize
1205 << ")");
1206 return false;
1207 }
1208 return true;
1209}
1210
1211bool
1213 WifiTxParameters& txParams,
1214 Time availableTime) const
1215{
1216 NS_ASSERT(msdu && msdu->GetHeader().IsQosData());
1217 NS_LOG_FUNCTION(this << *msdu << &txParams << availableTime);
1218
1219 // check if aggregating the given MSDU requires a different protection method
1220 NS_ASSERT(txParams.m_protection);
1221 Time protectionTime = txParams.m_protection->protectionTime;
1222
1223 std::unique_ptr<WifiProtection> protection;
1224 protection = GetProtectionManager()->TryAggregateMsdu(msdu, txParams);
1225 bool protectionSwapped = false;
1226
1227 if (protection)
1228 {
1229 // the protection method has changed, calculate the new protection time
1230 CalculateProtectionTime(protection.get());
1231 protectionTime = protection->protectionTime;
1232 // swap unique pointers, so that the txParams that is passed to the next
1233 // call to IsWithinLimitsIfAggregateMsdu is the most updated one
1234 txParams.m_protection.swap(protection);
1235 protectionSwapped = true;
1236 }
1237 NS_ASSERT(protectionTime != Time::Min());
1238
1239 // check if aggregating the given MSDU requires a different acknowledgment method
1240 NS_ASSERT(txParams.m_acknowledgment);
1241 Time acknowledgmentTime = txParams.m_acknowledgment->acknowledgmentTime;
1242
1243 std::unique_ptr<WifiAcknowledgment> acknowledgment;
1244 acknowledgment = GetAckManager()->TryAggregateMsdu(msdu, txParams);
1245 bool acknowledgmentSwapped = false;
1246
1247 if (acknowledgment)
1248 {
1249 // the acknowledgment method has changed, calculate the new acknowledgment time
1250 CalculateAcknowledgmentTime(acknowledgment.get());
1251 acknowledgmentTime = acknowledgment->acknowledgmentTime;
1252 // swap unique pointers, so that the txParams that is passed to the next
1253 // call to IsWithinLimitsIfAggregateMsdu is the most updated one
1254 txParams.m_acknowledgment.swap(acknowledgment);
1255 acknowledgmentSwapped = true;
1256 }
1257 NS_ASSERT(acknowledgmentTime != Time::Min());
1258
1259 Time ppduDurationLimit = Time::Min();
1260 if (availableTime != Time::Min())
1261 {
1262 ppduDurationLimit = availableTime - protectionTime - acknowledgmentTime;
1263 }
1264
1265 if (!IsWithinLimitsIfAggregateMsdu(msdu, txParams, ppduDurationLimit))
1266 {
1267 // adding MPDU failed, restore protection and acknowledgment methods
1268 // if they were swapped
1269 if (protectionSwapped)
1270 {
1271 txParams.m_protection.swap(protection);
1272 }
1273 if (acknowledgmentSwapped)
1274 {
1275 txParams.m_acknowledgment.swap(acknowledgment);
1276 }
1277 return false;
1278 }
1279
1280 // the given MPDU can be added, hence update the txParams
1281 txParams.AggregateMsdu(msdu);
1282 UpdateTxDuration(msdu->GetHeader().GetAddr1(), txParams);
1283
1284 return true;
1285}
1286
1287bool
1289 const WifiTxParameters& txParams,
1290 Time ppduDurationLimit) const
1291{
1292 NS_ASSERT(msdu && msdu->GetHeader().IsQosData());
1293 NS_LOG_FUNCTION(this << *msdu << &txParams << ppduDurationLimit);
1294
1295 std::pair<uint16_t, uint32_t> ret = txParams.GetSizeIfAggregateMsdu(msdu);
1296 Mac48Address receiver = msdu->GetHeader().GetAddr1();
1297 uint8_t tid = msdu->GetHeader().GetQosTid();
1298 WifiModulationClass modulation = txParams.m_txVector.GetModulationClass();
1299
1300 // Check that the limit on A-MSDU size is met
1301 uint16_t maxAmsduSize = m_msduAggregator->GetMaxAmsduSize(receiver, tid, modulation);
1302
1303 if (maxAmsduSize == 0)
1304 {
1305 NS_LOG_DEBUG("A-MSDU aggregation disabled");
1306 return false;
1307 }
1308
1309 if (ret.first > maxAmsduSize)
1310 {
1311 NS_LOG_DEBUG("No other MSDU can be aggregated: maximum A-MSDU size (" << maxAmsduSize
1312 << ") reached ");
1313 return false;
1314 }
1315
1316 const WifiTxParameters::PsduInfo* info = txParams.GetPsduInfo(msdu->GetHeader().GetAddr1());
1317 NS_ASSERT(info);
1318
1319 if (info->ampduSize > 0)
1320 {
1321 // the A-MSDU being built is aggregated to other MPDUs in an A-MPDU.
1322 // Check that the limit on A-MPDU size is met.
1323 if (!IsWithinAmpduSizeLimit(ret.second, receiver, tid, modulation))
1324 {
1325 return false;
1326 }
1327 }
1328
1329 return IsWithinSizeAndTimeLimits(ret.second, receiver, txParams, ppduDurationLimit);
1330}
1331
1332void
1334{
1335 NS_LOG_FUNCTION(this << *psdu << txVector);
1336
1338
1339 bool resetCw;
1340 MissedBlockAck(psdu, txVector, resetCw);
1341
1343
1344 if (resetCw)
1345 {
1347 }
1348 else
1349 {
1351 }
1352
1353 m_psdu = nullptr;
1355}
1356
1357void
1359 const WifiTxVector& txVector,
1360 bool& resetCw)
1361{
1362 NS_LOG_FUNCTION(this << psdu << txVector << resetCw);
1363
1364 auto recipient = psdu->GetAddr1();
1365 auto recipientMld = GetWifiRemoteStationManager()->GetMldAddress(recipient).value_or(recipient);
1366 bool isBar;
1367 uint8_t tid;
1368
1369 if (psdu->GetNMpdus() == 1 && psdu->GetHeader(0).IsBlockAckReq())
1370 {
1371 isBar = true;
1372 CtrlBAckRequestHeader baReqHdr;
1373 psdu->GetPayload(0)->PeekHeader(baReqHdr);
1374 tid = baReqHdr.GetTidInfo();
1375 }
1376 else
1377 {
1378 isBar = false;
1380 ->ReportAmpduTxStatus(recipient, 0, psdu->GetNMpdus(), 0, 0, txVector);
1381 std::set<uint8_t> tids = psdu->GetTids();
1382 NS_ABORT_MSG_IF(tids.size() > 1, "Multi-TID A-MPDUs not handled here");
1383 NS_ASSERT(!tids.empty());
1384 tid = *tids.begin();
1385 }
1386
1387 Ptr<QosTxop> edca = m_mac->GetQosTxop(tid);
1388
1389 if (edca->UseExplicitBarAfterMissedBlockAck() || isBar)
1390 {
1391 // we have to send a BlockAckReq, if needed
1392 if (GetBaManager(tid)->NeedBarRetransmission(tid, recipientMld))
1393 {
1394 NS_LOG_DEBUG("Missed Block Ack, transmit a BlockAckReq");
1405 if (isBar)
1406 {
1407 psdu->GetHeader(0).SetRetry();
1408 }
1409 else
1410 {
1411 // missed block ack after data frame with Implicit BAR Ack policy
1412 auto [reqHdr, hdr] = edca->PrepareBlockAckRequest(recipient, tid);
1413 GetBaManager(tid)->ScheduleBar(reqHdr, hdr);
1414 }
1415 resetCw = false;
1416 }
1417 else
1418 {
1419 NS_LOG_DEBUG("Missed Block Ack, do not transmit a BlockAckReq");
1420 // if a BA agreement exists, we can get here if there is no outstanding
1421 // MPDU whose lifetime has not expired yet.
1423 if (isBar)
1424 {
1425 DequeuePsdu(psdu);
1426 }
1427 if (m_mac->GetBaAgreementEstablishedAsOriginator(recipient, tid))
1428 {
1429 // schedule a BlockAckRequest to be sent only if there are data frames queued
1430 // for this recipient
1431 GetBaManager(tid)->AddToSendBarIfDataQueuedList(recipientMld, tid);
1432 }
1433 resetCw = true;
1434 }
1435 }
1436 else
1437 {
1438 // we have to retransmit the data frames, if needed
1439 if (!GetWifiRemoteStationManager()->NeedRetransmission(*psdu->begin()))
1440 {
1441 NS_LOG_DEBUG("Missed Block Ack, do not retransmit the data frames");
1443 for (const auto& mpdu : *PeekPointer(psdu))
1444 {
1446 DequeueMpdu(mpdu);
1447 }
1448 resetCw = true;
1449 }
1450 else
1451 {
1452 NS_LOG_DEBUG("Missed Block Ack, retransmit data frames");
1453 GetBaManager(tid)->NotifyMissedBlockAck(m_linkId, recipientMld, tid);
1454 resetCw = false;
1455 }
1456 }
1457}
1458
1459void
1461 Time durationId,
1462 WifiTxVector& blockAckTxVector,
1463 double rxSnr)
1464{
1465 NS_LOG_FUNCTION(this << durationId << blockAckTxVector << rxSnr);
1466
1467 WifiMacHeader hdr;
1469 auto addr1 = agreement.GetPeer();
1470 if (auto originator = GetWifiRemoteStationManager()->GetAffiliatedStaAddress(addr1))
1471 {
1472 addr1 = *originator;
1473 }
1474 hdr.SetAddr1(addr1);
1475 hdr.SetAddr2(m_self);
1476 hdr.SetDsNotFrom();
1477 hdr.SetDsNotTo();
1478
1479 CtrlBAckResponseHeader blockAck;
1480 blockAck.SetType(agreement.GetBlockAckType());
1481 blockAck.SetTidInfo(agreement.GetTid());
1482 agreement.FillBlockAckBitmap(&blockAck);
1483
1484 Ptr<Packet> packet = Create<Packet>();
1485 packet->AddHeader(blockAck);
1486 Ptr<WifiPsdu> psdu = GetWifiPsdu(Create<WifiMpdu>(packet, hdr), blockAckTxVector);
1487
1488 // 802.11-2016, Section 9.2.5.7: In a BlockAck frame transmitted in response
1489 // to a BlockAckReq frame or transmitted in response to a frame containing an
1490 // implicit block ack request, the Duration/ID field is set to the value obtained
1491 // from the Duration/ ID field of the frame that elicited the response minus the
1492 // time, in microseconds between the end of the PPDU carrying the frame that
1493 // elicited the response and the end of the PPDU carrying the BlockAck frame.
1494 Time baDurationId = durationId - m_phy->GetSifs() -
1495 m_phy->CalculateTxDuration(psdu, blockAckTxVector, m_phy->GetPhyBand());
1496 // The TXOP holder may exceed the TXOP limit in some situations (Sec. 10.22.2.8 of 802.11-2016)
1497 if (baDurationId.IsStrictlyNegative())
1498 {
1499 baDurationId = Seconds(0);
1500 }
1501 psdu->GetHeader(0).SetDuration(baDurationId);
1502
1503 SnrTag tag;
1504 tag.Set(rxSnr);
1505 psdu->GetPayload(0)->AddPacketTag(tag);
1506
1507 ForwardPsduDown(psdu, blockAckTxVector);
1508}
1509
1510void
1512 RxSignalInfo rxSignalInfo,
1513 const WifiTxVector& txVector,
1514 bool inAmpdu)
1515{
1516 // The received MPDU is either broadcast or addressed to this station
1517 NS_ASSERT(mpdu->GetHeader().GetAddr1().IsGroup() || mpdu->GetHeader().GetAddr1() == m_self);
1518
1519 double rxSnr = rxSignalInfo.snr;
1520 const WifiMacHeader& hdr = mpdu->GetHeader();
1521
1522 if (hdr.IsCtl())
1523 {
1524 if (hdr.IsCts() && m_txTimer.IsRunning() &&
1526 {
1527 NS_ABORT_MSG_IF(inAmpdu, "Received CTS as part of an A-MPDU");
1528 NS_ASSERT(hdr.GetAddr1() == m_self);
1529
1530 Mac48Address sender = m_psdu->GetAddr1();
1531 NS_LOG_DEBUG("Received CTS from=" << sender);
1532
1533 SnrTag tag;
1534 mpdu->GetPacket()->PeekPacketTag(tag);
1535 GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
1537 rxSnr,
1538 txVector.GetMode(),
1539 tag.Get());
1540
1541 m_txTimer.Cancel();
1545 this);
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.
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: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:469
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:296
Ptr< WifiMacQueue > GetWifiMacQueue() const
Return the packet queue associated with this Txop.
Definition: txop.cc:216
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:287
virtual void Queue(Ptr< Packet > packet, const WifiMacHeader &hdr)
Definition: txop.cc:501
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:936
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.
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:1358
TypeOfStation GetTypeOfStation() const
Return the type of station.
Definition: wifi-mac.cc:425
RecipientAgreementOptConstRef GetBaAgreementEstablishedAsRecipient(Mac48Address originator, uint8_t tid) const
Definition: wifi-mac.cc:1419
virtual Ptr< WifiMacQueue > GetTxopQueue(AcIndex ac) const
Get the wifi MAC queue of the (Qos)Txop associated with the given AC, if such (Qos)Txop is installed,...
Definition: wifi-mac.cc:543
OriginatorAgreementOptConstRef GetBaAgreementEstablishedAsOriginator(Mac48Address recipient, uint8_t tid) const
Definition: wifi-mac.cc:1405
Mac48Address GetAddress() const
Definition: wifi-mac.cc:450
Ptr< QosTxop > GetQosTxop(AcIndex ac) const
Accessor for a specified EDCA object.
Definition: wifi-mac.cc:497
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, 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_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: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:63
@ 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
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:133
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: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.
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