A Discrete-Event Network Simulator
API
ht-frame-exchange-manager.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2020 Universita' degli Studi di Napoli Federico II
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 * Author: Stefano Avallone <stavallo@unina.it>
18 */
19
21
22#include "ns3/abort.h"
23#include "ns3/ctrl-headers.h"
24#include "ns3/log.h"
25#include "ns3/mgt-headers.h"
26#include "ns3/recipient-block-ack-agreement.h"
27#include "ns3/snr-tag.h"
28#include "ns3/wifi-mac-queue.h"
29#include "ns3/wifi-utils.h"
30
31#include <array>
32#include <optional>
33
34#undef NS_LOG_APPEND_CONTEXT
35#define NS_LOG_APPEND_CONTEXT std::clog << "[link=" << +m_linkId << "][mac=" << m_self << "] "
36
37namespace ns3
38{
39
40NS_LOG_COMPONENT_DEFINE("HtFrameExchangeManager");
41
42NS_OBJECT_ENSURE_REGISTERED(HtFrameExchangeManager);
43
44TypeId
46{
47 static TypeId tid = TypeId("ns3::HtFrameExchangeManager")
49 .AddConstructor<HtFrameExchangeManager>()
50 .SetGroupName("Wifi");
51 return tid;
52}
53
55{
56 NS_LOG_FUNCTION(this);
57 m_msduAggregator = CreateObject<MsduAggregator>();
58 m_mpduAggregator = CreateObject<MpduAggregator>();
59}
60
62{
64}
65
66void
68{
69 NS_LOG_FUNCTION(this);
70 m_agreements.clear();
71 m_pendingAgreements.clear();
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 (qosTxop->GetBaManager()->ExistsAgreement(recipient, tid) &&
117 !qosTxop->GetBaManager()->ExistsAgreementInState(recipient,
118 tid,
120 {
121 establish = false;
122 }
123 else
124 {
125 WifiContainerQueueId queueId{WIFI_QOSDATA_UNICAST_QUEUE, recipient, tid};
126 uint32_t packets = qosTxop->GetWifiMacQueue()->GetNPackets(queueId);
127 establish =
128 ((qosTxop->GetBlockAckThreshold() > 0 && packets >= qosTxop->GetBlockAckThreshold()) ||
129 (m_mpduAggregator->GetMaxAmpduSize(recipient, tid, WIFI_MOD_CLASS_HT) > 0 &&
130 packets > 1) ||
132 }
133
134 NS_LOG_FUNCTION(this << recipient << +tid << establish);
135 return establish;
136}
137
138void
140 uint8_t tid,
141 uint16_t startingSeq,
142 uint16_t timeout,
143 bool immediateBAck)
144{
145 NS_LOG_FUNCTION(this << dest << +tid << startingSeq << timeout << immediateBAck);
146 NS_LOG_DEBUG("Send ADDBA request to " << dest);
147
148 WifiMacHeader hdr;
150 hdr.SetAddr1(dest);
151 hdr.SetAddr2(m_self);
152 hdr.SetAddr3(m_bssid);
153 hdr.SetDsNotTo();
154 hdr.SetDsNotFrom();
155
156 WifiActionHeader actionHdr;
160
161 Ptr<Packet> packet = Create<Packet>();
162 // Setting ADDBARequest header
164 reqHdr.SetAmsduSupport(true);
165 if (immediateBAck)
166 {
167 reqHdr.SetImmediateBlockAck();
168 }
169 else
170 {
171 reqHdr.SetDelayedBlockAck();
172 }
173 reqHdr.SetTid(tid);
174 /* For now we don't use buffer size field in the ADDBA request frame. The recipient
175 * will choose how many packets it can receive under block ack.
176 */
177 reqHdr.SetBufferSize(0);
178 reqHdr.SetTimeout(timeout);
179 // set the starting sequence number for the BA agreement
180 reqHdr.SetStartingSequence(startingSeq);
181
182 GetBaManager(tid)->CreateAgreement(&reqHdr, dest);
183
184 packet->AddHeader(reqHdr);
185 packet->AddHeader(actionHdr);
186
187 Ptr<WifiMpdu> mpdu = Create<WifiMpdu>(packet, hdr);
188
189 // get the sequence number for the ADDBA Request management frame
190 uint16_t sequence = m_txMiddle->GetNextSequenceNumberFor(&mpdu->GetHeader());
191 mpdu->GetHeader().SetSequenceNumber(sequence);
192
193 WifiTxParameters txParams;
194 txParams.m_txVector =
196 txParams.m_protection = std::unique_ptr<WifiProtection>(new WifiNoProtection);
197 txParams.m_acknowledgment = GetAckManager()->TryAddMpdu(mpdu, txParams);
198
199 // Wifi MAC queue scheduler is expected to prioritize management frames
200 m_mac->GetQosTxop(tid)->GetWifiMacQueue()->Enqueue(mpdu);
201 SendMpduWithProtection(mpdu, txParams);
202}
203
204void
206 Mac48Address originator)
207{
208 NS_LOG_FUNCTION(this << originator);
209 WifiMacHeader hdr;
211 hdr.SetAddr1(originator);
212 hdr.SetAddr2(m_self);
213 hdr.SetAddr3(m_bssid);
214 hdr.SetDsNotFrom();
215 hdr.SetDsNotTo();
216
218 StatusCode code;
219 code.SetSuccess();
220 respHdr.SetStatusCode(code);
221 // Here a control about queues type?
222 respHdr.SetAmsduSupport(reqHdr->IsAmsduSupported());
223
224 if (reqHdr->IsImmediateBlockAck())
225 {
226 respHdr.SetImmediateBlockAck();
227 }
228 else
229 {
230 respHdr.SetDelayedBlockAck();
231 }
232 respHdr.SetTid(reqHdr->GetTid());
233
235 respHdr.SetTimeout(reqHdr->GetTimeout());
236
237 WifiActionHeader actionHdr;
241
242 Ptr<Packet> packet = Create<Packet>();
243 packet->AddHeader(respHdr);
244 packet->AddHeader(actionHdr);
245
246 CreateBlockAckAgreement(&respHdr, originator, reqHdr->GetStartingSequence());
247
248 auto mpdu = Create<WifiMpdu>(packet, hdr);
249
250 /*
251 * It is possible (though, unlikely) that at this point there are other ADDBA_RESPONSE frame(s)
252 * in the MAC queue. This may happen if the recipient receives an ADDBA_REQUEST frame, enqueues
253 * an ADDBA_RESPONSE frame, but is not able to successfully transmit it before the timer to
254 * wait for ADDBA_RESPONSE expires at the originator. The latter may then send another
255 * ADDBA_REQUEST frame, which triggers the creation of another ADDBA_RESPONSE frame.
256 * The first ADDBA_RESPONSE frame that is acknowledged causes the Block Ack agreement to be
257 * moved from the queue of pending agreements to the queue of establish agreements; the next
258 * one will find no pending agreement, thus causing the simulation to abort.
259 * As a solution, we keep track of the previously enqueued ADDBA_RESPONSE frame (if any),
260 * dequeue it and replace it with the new ADDBA_RESPONSE frame.
261 */
262
263 // remove any pending ADDBA_RESPONSE frame
264 AgreementKey key(originator, reqHdr->GetTid());
265 if (auto it = m_pendingAddBaResp.find(key); it != m_pendingAddBaResp.end())
266 {
267 NS_ASSERT_MSG(it->second, "The pointer to the pending ADDBA_RESPONSE cannot be null");
268 DequeueMpdu(it->second);
269 m_pendingAddBaResp.erase(it);
270 }
271 // store the new ADDBA_RESPONSE frame
272 m_pendingAddBaResp[key] = mpdu;
273
274 // It is unclear which queue this frame should go into. For now we
275 // bung it into the queue corresponding to the TID for which we are
276 // establishing an agreement, and push it to the head.
277 // Wifi MAC queue scheduler is expected to prioritize management frames
278 m_mac->GetQosTxop(reqHdr->GetTid())->Queue(mpdu);
279}
280
281uint16_t
283{
284 return 64;
285}
286
287void
288HtFrameExchangeManager::SendDelbaFrame(Mac48Address addr, uint8_t tid, bool byOriginator)
289{
290 NS_LOG_FUNCTION(this << addr << +tid << byOriginator);
291 WifiMacHeader hdr;
293 hdr.SetAddr1(addr);
294 hdr.SetAddr2(m_self);
295 hdr.SetAddr3(m_bssid);
296 hdr.SetDsNotTo();
297 hdr.SetDsNotFrom();
298
299 MgtDelBaHeader delbaHdr;
300 delbaHdr.SetTid(tid);
301 if (byOriginator)
302 {
303 delbaHdr.SetByOriginator();
304 GetBaManager(tid)->DestroyAgreement(addr, tid);
305 }
306 else
307 {
308 delbaHdr.SetByRecipient();
309 DestroyBlockAckAgreement(addr, tid);
310 }
311
312 WifiActionHeader actionHdr;
316
317 Ptr<Packet> packet = Create<Packet>();
318 packet->AddHeader(delbaHdr);
319 packet->AddHeader(actionHdr);
320
321 m_mac->GetQosTxop(tid)->GetWifiMacQueue()->Enqueue(Create<WifiMpdu>(packet, hdr));
322}
323
324void
326 Mac48Address originator,
327 uint16_t startingSeq)
328{
329 NS_LOG_FUNCTION(this << *respHdr << originator << startingSeq);
330 uint8_t tid = respHdr->GetTid();
331
333 originator,
334 respHdr->IsAmsduSupported(),
335 tid,
336 respHdr->GetBufferSize(),
337 respHdr->GetTimeout(),
338 startingSeq,
339 GetWifiRemoteStationManager()->GetHtSupported() &&
340 GetWifiRemoteStationManager()->GetHtSupported(originator));
341 agreement.SetMacRxMiddle(m_rxMiddle);
342 if (respHdr->IsImmediateBlockAck())
343 {
344 agreement.SetImmediateBlockAck();
345 }
346 else
347 {
348 agreement.SetDelayedBlockAck();
349 }
350
351 if (respHdr->GetTimeout() != 0)
352 {
353 Time timeout = MicroSeconds(1024 * agreement.GetTimeout());
354
357 this,
358 originator,
359 tid,
360 false);
361 }
362
363 m_pendingAgreements.insert_or_assign({originator, tid}, agreement);
364}
365
366void
368{
369 NS_LOG_FUNCTION(this << originator << +tid);
370
371 auto agreementIt = m_agreements.find({originator, tid});
372 if (agreementIt != m_agreements.end())
373 {
374 // forward up the buffered MPDUs before destroying the agreement
375 agreementIt->second.Flush();
376 m_agreements.erase(agreementIt);
377 }
378}
379
380bool
381HtFrameExchangeManager::StartFrameExchange(Ptr<QosTxop> edca, Time availableTime, bool initialFrame)
382{
383 NS_LOG_FUNCTION(this << edca << availableTime << initialFrame);
384
385 // First, check if there is a BAR to be transmitted
386 if (SendMpduFromBaManager(edca, availableTime, initialFrame))
387 {
388 return true;
389 }
390
391 Ptr<WifiMpdu> peekedItem = edca->PeekNextMpdu(m_linkId);
392
393 // Even though channel access is requested when the queue is not empty, at
394 // the time channel access is granted the lifetime of the packet might be
395 // expired and the queue might be empty.
396 if (!peekedItem)
397 {
398 NS_LOG_DEBUG("No frames available for transmission");
399 return false;
400 }
401
402 const WifiMacHeader& hdr = peekedItem->GetHeader();
403 // setup a Block Ack agreement if needed
404 if (hdr.IsQosData() && !hdr.GetAddr1().IsGroup() &&
406 {
407 // if the peeked MPDU has been already transmitted, use its sequence number
408 // as the starting sequence number for the BA agreement, otherwise use the
409 // next available sequence number
410 uint16_t startingSeq =
411 (hdr.IsRetry()
412 ? hdr.GetSequenceNumber()
413 : m_txMiddle->GetNextSeqNumberByTidAndAddress(hdr.GetQosTid(), hdr.GetAddr1()));
415 hdr.GetQosTid(),
416 startingSeq,
418 true);
419 return true;
420 }
421
422 // Use SendDataFrame if we can try aggregation
423 if (hdr.IsQosData() && !hdr.GetAddr1().IsGroup() && !peekedItem->IsFragment() &&
424 !GetWifiRemoteStationManager()->NeedFragmentation(peekedItem))
425 {
426 return SendDataFrame(peekedItem, availableTime, initialFrame);
427 }
428
429 // Use the QoS FEM to transmit the frame in all the other cases, i.e.:
430 // - the frame is not a QoS data frame
431 // - the frame is a broadcast QoS data frame
432 // - the frame is a fragment
433 // - the frame must be fragmented
434 return QosFrameExchangeManager::StartFrameExchange(edca, availableTime, initialFrame);
435}
436
437bool
439 Time availableTime,
440 bool initialFrame)
441{
442 NS_LOG_FUNCTION(this << edca << availableTime << initialFrame);
443
444 // First, check if there is a BAR to be transmitted
445 Ptr<const WifiMpdu> peekedItem = edca->GetBaManager()->GetBar(false);
446
447 if (!peekedItem)
448 {
449 NS_LOG_DEBUG("Block Ack Manager returned no frame to send");
450 return false;
451 }
452
453 NS_ASSERT(peekedItem->GetHeader().IsBlockAckReq());
454
455 // Prepare the TX parameters. Note that the default ack manager expects the
456 // data TxVector in the m_txVector field to compute the BlockAck TxVector.
457 // The m_txVector field of the TX parameters is set to the BlockAckReq TxVector
458 // a few lines below.
459 WifiTxParameters txParams;
460 txParams.m_txVector =
462 txParams.m_protection = std::unique_ptr<WifiProtection>(new WifiNoProtection);
463 txParams.m_acknowledgment = GetAckManager()->TryAddMpdu(peekedItem, txParams);
464
466
467 WifiBlockAck* blockAcknowledgment = static_cast<WifiBlockAck*>(txParams.m_acknowledgment.get());
468 CalculateAcknowledgmentTime(blockAcknowledgment);
469 // the BlockAckReq frame is sent using the same TXVECTOR as the BlockAck frame
470 txParams.m_txVector = blockAcknowledgment->blockAckTxVector;
471
472 Time barTxDuration = m_phy->CalculateTxDuration(peekedItem->GetSize(),
473 blockAcknowledgment->blockAckTxVector,
474 m_phy->GetPhyBand());
475
476 // if the available time is limited and we are not transmitting the initial
477 // frame of the TXOP, we have to check that this frame and its response fit
478 // within the given time limits
479 if (availableTime != Time::Min() && !initialFrame &&
480 barTxDuration + m_phy->GetSifs() + blockAcknowledgment->acknowledgmentTime > availableTime)
481 {
482 NS_LOG_DEBUG("Not enough time to send the BAR frame returned by the Block Ack Manager");
483 return false;
484 }
485
486 // we can transmit the BlockAckReq frame
487 Ptr<const WifiMpdu> mpdu = edca->GetBaManager()->GetBar();
488 SendPsduWithProtection(GetWifiPsdu(Copy(mpdu), txParams.m_txVector), txParams);
489 return true;
490}
491
492bool
494 Time availableTime,
495 bool initialFrame)
496{
497 NS_ASSERT(peekedItem && peekedItem->GetHeader().IsQosData() &&
498 !peekedItem->GetHeader().GetAddr1().IsBroadcast() && !peekedItem->IsFragment());
499 NS_LOG_FUNCTION(this << *peekedItem << availableTime << initialFrame);
500
501 Ptr<QosTxop> edca = m_mac->GetQosTxop(peekedItem->GetHeader().GetQosTid());
502 WifiTxParameters txParams;
503 txParams.m_txVector =
505 Ptr<WifiMpdu> mpdu =
506 edca->GetNextMpdu(m_linkId, peekedItem, txParams, availableTime, initialFrame);
507
508 if (!mpdu)
509 {
510 NS_LOG_DEBUG("Not enough time to transmit a frame");
511 return false;
512 }
513
514 // try A-MPDU aggregation
515 std::vector<Ptr<WifiMpdu>> mpduList =
516 m_mpduAggregator->GetNextAmpdu(mpdu, txParams, availableTime);
517 NS_ASSERT(txParams.m_acknowledgment);
518
519 if (mpduList.size() > 1)
520 {
521 // A-MPDU aggregation succeeded
522 SendPsduWithProtection(Create<WifiPsdu>(std::move(mpduList)), txParams);
523 }
524 else if (txParams.m_acknowledgment->method == WifiAcknowledgment::BAR_BLOCK_ACK)
525 {
526 // a QoS data frame using the Block Ack policy can be followed by a BlockAckReq
527 // frame and a BlockAck frame. Such a sequence is handled by the HT FEM
528 SendPsduWithProtection(Create<WifiPsdu>(mpdu, false), txParams);
529 }
530 else
531 {
532 // transmission can be handled by the base FEM
533 SendMpduWithProtection(mpdu, txParams);
534 }
535
536 return true;
537}
538
539void
541{
542 NS_LOG_FUNCTION(this << acknowledgment);
543 NS_ASSERT(acknowledgment);
544
545 if (acknowledgment->method == WifiAcknowledgment::BLOCK_ACK)
546 {
547 WifiBlockAck* blockAcknowledgment = static_cast<WifiBlockAck*>(acknowledgment);
548 Time baTxDuration = m_phy->CalculateTxDuration(GetBlockAckSize(blockAcknowledgment->baType),
549 blockAcknowledgment->blockAckTxVector,
550 m_phy->GetPhyBand());
551 blockAcknowledgment->acknowledgmentTime = m_phy->GetSifs() + baTxDuration;
552 }
553 else if (acknowledgment->method == WifiAcknowledgment::BAR_BLOCK_ACK)
554 {
555 WifiBarBlockAck* barBlockAcknowledgment = static_cast<WifiBarBlockAck*>(acknowledgment);
556 Time barTxDuration =
558 barBlockAcknowledgment->blockAckReqTxVector,
559 m_phy->GetPhyBand());
560 Time baTxDuration =
561 m_phy->CalculateTxDuration(GetBlockAckSize(barBlockAcknowledgment->baType),
562 barBlockAcknowledgment->blockAckTxVector,
563 m_phy->GetPhyBand());
564 barBlockAcknowledgment->acknowledgmentTime =
565 2 * m_phy->GetSifs() + barTxDuration + baTxDuration;
566 }
567 else
568 {
570 }
571}
572
573void
575{
576 ForwardPsduDown(GetWifiPsdu(mpdu, txVector), txVector);
577}
578
581{
582 return Create<WifiPsdu>(mpdu, false);
583}
584
585void
587{
588 NS_LOG_FUNCTION(this << *mpdu);
589
590 if (mpdu->GetHeader().IsQosData())
591 {
592 uint8_t tid = mpdu->GetHeader().GetQosTid();
593 Ptr<QosTxop> edca = m_mac->GetQosTxop(tid);
594
595 if (edca->GetBaAgreementEstablished(mpdu->GetHeader().GetAddr1(), tid))
596 {
597 // notify the BA manager that the MPDU was acknowledged
598 edca->GetBaManager()->NotifyGotAck(mpdu);
599 }
600 }
601 else if (mpdu->GetHeader().IsAction())
602 {
603 WifiActionHeader actionHdr;
604 Ptr<Packet> p = mpdu->GetPacket()->Copy();
605 p->RemoveHeader(actionHdr);
606 if (actionHdr.GetCategory() == WifiActionHeader::BLOCK_ACK)
607 {
609 {
610 MgtDelBaHeader delBa;
611 p->PeekHeader(delBa);
612 if (delBa.IsByOriginator())
613 {
614 GetBaManager(delBa.GetTid())
615 ->DestroyAgreement(mpdu->GetHeader().GetAddr1(), delBa.GetTid());
616 }
617 else
618 {
619 DestroyBlockAckAgreement(mpdu->GetHeader().GetAddr1(), delBa.GetTid());
620 }
621 }
623 {
624 // Setup ADDBA response timeout
626 p->PeekHeader(addBa);
627 Ptr<QosTxop> edca = m_mac->GetQosTxop(addBa.GetTid());
630 edca,
631 mpdu->GetHeader().GetAddr1(),
632 addBa.GetTid());
633 }
635 {
636 // The recipient Block Ack agreement can be moved from the pending queue
637 // to the queue of established Block Ack agreements
639 p->PeekHeader(addBa);
640 AgreementKey key(mpdu->GetHeader().GetAddr1(), addBa.GetTid());
641 auto nh = m_pendingAgreements.extract(key);
642 NS_ASSERT_MSG(!nh.empty(),
643 "Pending agreement {" << key.first << ", " << +key.second
644 << "} not found");
645 m_agreements.erase(nh.key());
646 m_agreements.insert(std::move(nh));
647 m_pendingAddBaResp.erase(key);
648 }
649 }
650 }
652}
653
654void
656{
657 NS_LOG_DEBUG(this);
658
659 if (m_edca && m_edca->GetTxopLimit(m_linkId).IsZero() && m_edca->GetBaManager()->GetBar(false))
660 {
661 // A TXOP limit of 0 indicates that the TXOP holder may transmit or cause to
662 // be transmitted (as responses) the following within the current TXOP:
663 // f) Any number of BlockAckReq frames
664 // (Sec. 10.22.2.8 of 802.11-2016)
665 NS_LOG_DEBUG("Schedule a transmission from Block Ack Manager in a SIFS");
668
669 // TXOP limit is null, hence the txopDuration parameter is unused
671 }
672 else
673 {
675 }
676}
677
678void
680{
681 NS_LOG_FUNCTION(this << *mpdu);
682
683 if (mpdu->GetHeader().IsQosData())
684 {
685 GetBaManager(mpdu->GetHeader().GetQosTid())->NotifyDiscardedMpdu(mpdu);
686 }
687 else if (mpdu->GetHeader().IsAction())
688 {
689 WifiActionHeader actionHdr;
690 mpdu->GetPacket()->PeekHeader(actionHdr);
691 if (actionHdr.GetCategory() == WifiActionHeader::BLOCK_ACK)
692 {
693 uint8_t tid = GetTid(mpdu->GetPacket(), mpdu->GetHeader());
694 if (GetBaManager(tid)->ExistsAgreementInState(mpdu->GetHeader().GetAddr1(),
695 tid,
697 {
698 NS_LOG_DEBUG("No ACK after ADDBA request");
699 GetBaManager(tid)->NotifyAgreementNoReply(mpdu->GetHeader().GetAddr1(), tid);
700 Ptr<QosTxop> qosTxop = m_mac->GetQosTxop(tid);
703 qosTxop,
704 mpdu->GetHeader().GetAddr1(),
705 tid);
706 }
707 }
708 }
710}
711
712void
714{
715 NS_LOG_FUNCTION(this << *mpdu);
716
717 if (mpdu->GetHeader().IsQosData())
718 {
719 uint8_t tid = mpdu->GetHeader().GetQosTid();
720 Ptr<QosTxop> edca = m_mac->GetQosTxop(tid);
721
722 if (edca->GetBaAgreementEstablished(mpdu->GetHeader().GetAddr1(), tid))
723 {
724 // notify the BA manager that the MPDU was not acknowledged
725 edca->GetBaManager()->NotifyMissedAck(mpdu);
726 return;
727 }
728 }
730}
731
732void
734{
735 NS_LOG_FUNCTION(this << *mpdu);
736
737 // the MPDU should be still in the queue, unless it expired.
738 const WifiMacHeader& hdr = mpdu->GetHeader();
739 if (hdr.IsQosData())
740 {
741 uint8_t tid = hdr.GetQosTid();
742 Ptr<QosTxop> edca = m_mac->GetQosTxop(tid);
743
744 if (edca->GetBaAgreementEstablished(hdr.GetAddr1(), tid) && !hdr.IsRetry())
745 {
746 // The MPDU has never been transmitted, so we can make its sequence
747 // number available again if it is lower than the sequence number
748 // maintained by the MAC TX middle
749 uint16_t currentNextSeq = m_txMiddle->PeekNextSequenceNumberFor(&hdr);
750 uint16_t startingSeq = edca->GetBaStartingSequence(hdr.GetAddr1(), tid);
751
752 if (BlockAckAgreement::GetDistance(hdr.GetSequenceNumber(), startingSeq) <
753 BlockAckAgreement::GetDistance(currentNextSeq, startingSeq))
754 {
755 m_txMiddle->SetSequenceNumberFor(&hdr);
756 }
757
758 return;
759 }
760 }
762}
763
764Time
766{
767 NS_LOG_FUNCTION(this << txDuration << &txParams);
768
770
772 {
773 NS_ASSERT(txParams.m_acknowledgment &&
774 txParams.m_acknowledgment->acknowledgmentTime != Time::Min());
775 return txParams.m_acknowledgment->acknowledgmentTime;
776 }
777
778 // under multiple protection settings, if the TXOP limit is not null, Duration/ID
779 // is set to cover the remaining TXOP time (Sec. 9.2.5.2 of 802.11-2016).
780 // The TXOP holder may exceed the TXOP limit in some situations (Sec. 10.22.2.8
781 // of 802.11-2016)
782 return std::max(m_edca->GetRemainingTxop(m_linkId) - txDuration, Seconds(0));
783}
784
785void
787{
788 NS_LOG_FUNCTION(this << psdu << &txParams);
789
790 m_psdu = psdu;
791 m_txParams = std::move(txParams);
792
793#ifdef NS3_BUILD_PROFILE_DEBUG
794 // If protection is required, the MPDUs must be stored in some queue because
795 // they are not put back in a queue if the RTS/CTS exchange fails
797 {
798 for (const auto& mpdu : *PeekPointer(m_psdu))
799 {
800 NS_ASSERT(mpdu->GetHeader().IsCtl() || mpdu->IsQueued());
801 }
802 }
803#endif
804
805 // Make sure that the acknowledgment time has been computed, so that SendRts()
806 // and SendCtsToSelf() can reuse this value.
808
809 if (m_txParams.m_acknowledgment->acknowledgmentTime == Time::Min())
810 {
812 }
813
814 // Set QoS Ack policy
816
818 {
820 }
822 {
824 }
825 else if (m_txParams.m_protection->method == WifiProtection::NONE)
826 {
827 SendPsdu();
828 }
829 else
830 {
831 NS_ABORT_MSG("Unknown protection type");
832 }
833}
834
835void
837{
838 NS_LOG_FUNCTION(this << *rts << txVector);
839
840 if (!m_psdu)
841 {
842 // A CTS Timeout occurred when protecting a single MPDU is handled by the
843 // parent classes
845 return;
846 }
847
849 m_psdu = nullptr;
850}
851
852void
854{
855 NS_LOG_FUNCTION(this);
856
857 Time txDuration =
859
861
863 {
865
866 std::set<uint8_t> tids = m_psdu->GetTids();
867 NS_ASSERT_MSG(tids.size() <= 1, "Multi-TID A-MPDUs are not supported");
868
869 if (tids.size() == 0 || m_psdu->GetAckPolicyForTid(*tids.begin()) == WifiMacHeader::NO_ACK)
870 {
871 // No acknowledgment, hence dequeue the PSDU if it is stored in a queue
873 }
874 }
876 {
878
879 // the timeout duration is "aSIFSTime + aSlotTime + aRxPHYStartDelay, starting
880 // at the PHY-TXEND.confirm primitive" (section 10.3.2.9 or 10.22.2.2 of 802.11-2016).
881 // aRxPHYStartDelay equals the time to transmit the PHY header.
882 WifiBlockAck* blockAcknowledgment =
883 static_cast<WifiBlockAck*>(m_txParams.m_acknowledgment.get());
884
885 Time timeout =
886 txDuration + m_phy->GetSifs() + m_phy->GetSlot() +
890 timeout,
892 this,
893 m_psdu,
896 }
898 {
900
901 // schedule the transmission of a BAR in a SIFS
902 std::set<uint8_t> tids = m_psdu->GetTids();
903 NS_ABORT_MSG_IF(tids.size() > 1,
904 "Acknowledgment method incompatible with a Multi-TID A-MPDU");
905 uint8_t tid = *tids.begin();
906
907 Ptr<QosTxop> edca = m_mac->GetQosTxop(tid);
909
911 }
912 else
913 {
914 NS_ABORT_MSG("Unable to handle the selected acknowledgment method ("
915 << m_txParams.m_acknowledgment.get() << ")");
916 }
917
918 // transmit the PSDU
919 if (m_psdu->GetNMpdus() > 1)
920 {
922 }
923 else
924 {
926 }
927
929 {
930 // we are done in case the A-MPDU does not require acknowledgment
931 m_psdu = nullptr;
932 }
933}
934
935void
937{
938 NS_LOG_FUNCTION(this << psdu);
939
940 // use an array to avoid computing the queue size for every MPDU in the PSDU
941 std::array<std::optional<uint8_t>, 8> queueSizeForTid;
942
943 for (const auto& mpdu : *PeekPointer(psdu))
944 {
945 WifiMacHeader& hdr = mpdu->GetHeader();
946
947 if (hdr.IsQosData())
948 {
949 uint8_t tid = hdr.GetQosTid();
950 Ptr<QosTxop> edca = m_mac->GetQosTxop(tid);
951
952 if (m_mac->GetTypeOfStation() == STA && (m_setQosQueueSize || hdr.IsQosEosp()))
953 {
954 // set the Queue Size subfield of the QoS Control field
955 if (!queueSizeForTid[tid].has_value())
956 {
957 queueSizeForTid[tid] = edca->GetQosQueueSize(tid, hdr.GetAddr1());
958 }
959
960 hdr.SetQosEosp();
961 hdr.SetQosQueueSize(queueSizeForTid[tid].value());
962 }
963
964 if (hdr.HasData())
965 {
966 edca->CompleteMpduTx(mpdu);
967 }
968 }
969 }
970}
971
972void
974{
975 NS_LOG_DEBUG(this << psdu);
976
977 for (const auto& mpdu : *PeekPointer(psdu))
978 {
979 DequeueMpdu(mpdu);
980 }
981}
982
983void
985{
986 NS_LOG_FUNCTION(this << psdu << txVector);
987
988 NS_LOG_DEBUG("Transmitting a PSDU: " << *psdu << " TXVECTOR: " << txVector);
989 NotifyTxToEdca(psdu);
990
991 if (psdu->IsAggregate())
992 {
993 txVector.SetAggregation(true);
994 }
995
996 m_phy->Send(psdu, txVector);
997}
998
999bool
1001 const WifiTxParameters& txParams,
1002 Time ppduDurationLimit) const
1003{
1004 NS_ASSERT(mpdu);
1005 NS_LOG_FUNCTION(this << *mpdu << &txParams << ppduDurationLimit);
1006
1007 Mac48Address receiver = mpdu->GetHeader().GetAddr1();
1008 uint32_t ampduSize = txParams.GetSizeIfAddMpdu(mpdu);
1009
1010 if (txParams.GetSize(receiver) > 0)
1011 {
1012 // we are attempting to perform A-MPDU aggregation, hence we have to check
1013 // that we meet the limit on the max A-MPDU size
1014 uint8_t tid;
1015 const WifiTxParameters::PsduInfo* info;
1016
1017 if (mpdu->GetHeader().IsQosData())
1018 {
1019 tid = mpdu->GetHeader().GetQosTid();
1020 }
1021 else if ((info = txParams.GetPsduInfo(receiver)) && !info->seqNumbers.empty())
1022 {
1023 tid = info->seqNumbers.begin()->first;
1024 }
1025 else
1026 {
1027 NS_ABORT_MSG("Cannot aggregate a non-QoS data frame to an A-MPDU that does"
1028 " not contain any QoS data frame");
1029 }
1030
1031 WifiModulationClass modulation = txParams.m_txVector.GetModulationClass();
1032
1033 if (!IsWithinAmpduSizeLimit(ampduSize, receiver, tid, modulation))
1034 {
1035 return false;
1036 }
1037 }
1038
1039 return IsWithinSizeAndTimeLimits(ampduSize, receiver, txParams, ppduDurationLimit);
1040}
1041
1042bool
1044 Mac48Address receiver,
1045 uint8_t tid,
1046 WifiModulationClass modulation) const
1047{
1048 NS_LOG_FUNCTION(this << ampduSize << receiver << +tid << modulation);
1049
1050 uint32_t maxAmpduSize = m_mpduAggregator->GetMaxAmpduSize(receiver, tid, modulation);
1051
1052 if (maxAmpduSize == 0)
1053 {
1054 NS_LOG_DEBUG("A-MPDU aggregation disabled");
1055 return false;
1056 }
1057
1058 if (ampduSize > maxAmpduSize)
1059 {
1060 NS_LOG_DEBUG("the frame does not meet the constraint on max A-MPDU size (" << maxAmpduSize
1061 << ")");
1062 return false;
1063 }
1064 return true;
1065}
1066
1067bool
1069 WifiTxParameters& txParams,
1070 Time availableTime) const
1071{
1072 NS_ASSERT(msdu && msdu->GetHeader().IsQosData());
1073 NS_LOG_FUNCTION(this << *msdu << &txParams << availableTime);
1074
1075 // check if aggregating the given MSDU requires a different protection method
1076 NS_ASSERT(txParams.m_protection);
1077 Time protectionTime = txParams.m_protection->protectionTime;
1078
1079 std::unique_ptr<WifiProtection> protection;
1080 protection = GetProtectionManager()->TryAggregateMsdu(msdu, txParams);
1081 bool protectionSwapped = false;
1082
1083 if (protection)
1084 {
1085 // the protection method has changed, calculate the new protection time
1086 CalculateProtectionTime(protection.get());
1087 protectionTime = protection->protectionTime;
1088 // swap unique pointers, so that the txParams that is passed to the next
1089 // call to IsWithinLimitsIfAggregateMsdu is the most updated one
1090 txParams.m_protection.swap(protection);
1091 protectionSwapped = true;
1092 }
1093 NS_ASSERT(protectionTime != Time::Min());
1094
1095 // check if aggregating the given MSDU requires a different acknowledgment method
1096 NS_ASSERT(txParams.m_acknowledgment);
1097 Time acknowledgmentTime = txParams.m_acknowledgment->acknowledgmentTime;
1098
1099 std::unique_ptr<WifiAcknowledgment> acknowledgment;
1100 acknowledgment = GetAckManager()->TryAggregateMsdu(msdu, txParams);
1101 bool acknowledgmentSwapped = false;
1102
1103 if (acknowledgment)
1104 {
1105 // the acknowledgment method has changed, calculate the new acknowledgment time
1106 CalculateAcknowledgmentTime(acknowledgment.get());
1107 acknowledgmentTime = acknowledgment->acknowledgmentTime;
1108 // swap unique pointers, so that the txParams that is passed to the next
1109 // call to IsWithinLimitsIfAggregateMsdu is the most updated one
1110 txParams.m_acknowledgment.swap(acknowledgment);
1111 acknowledgmentSwapped = true;
1112 }
1113 NS_ASSERT(acknowledgmentTime != Time::Min());
1114
1115 Time ppduDurationLimit = Time::Min();
1116 if (availableTime != Time::Min())
1117 {
1118 ppduDurationLimit = availableTime - protectionTime - acknowledgmentTime;
1119 }
1120
1121 if (!IsWithinLimitsIfAggregateMsdu(msdu, txParams, ppduDurationLimit))
1122 {
1123 // adding MPDU failed, restore protection and acknowledgment methods
1124 // if they were swapped
1125 if (protectionSwapped)
1126 {
1127 txParams.m_protection.swap(protection);
1128 }
1129 if (acknowledgmentSwapped)
1130 {
1131 txParams.m_acknowledgment.swap(acknowledgment);
1132 }
1133 return false;
1134 }
1135
1136 // the given MPDU can be added, hence update the txParams
1137 txParams.AggregateMsdu(msdu);
1138 UpdateTxDuration(msdu->GetHeader().GetAddr1(), txParams);
1139
1140 return true;
1141}
1142
1143bool
1145 const WifiTxParameters& txParams,
1146 Time ppduDurationLimit) const
1147{
1148 NS_ASSERT(msdu && msdu->GetHeader().IsQosData());
1149 NS_LOG_FUNCTION(this << *msdu << &txParams << ppduDurationLimit);
1150
1151 std::pair<uint16_t, uint32_t> ret = txParams.GetSizeIfAggregateMsdu(msdu);
1152 Mac48Address receiver = msdu->GetHeader().GetAddr1();
1153 uint8_t tid = msdu->GetHeader().GetQosTid();
1154 WifiModulationClass modulation = txParams.m_txVector.GetModulationClass();
1155
1156 // Check that the limit on A-MSDU size is met
1157 uint16_t maxAmsduSize = m_msduAggregator->GetMaxAmsduSize(receiver, tid, modulation);
1158
1159 if (maxAmsduSize == 0)
1160 {
1161 NS_LOG_DEBUG("A-MSDU aggregation disabled");
1162 return false;
1163 }
1164
1165 if (ret.first > maxAmsduSize)
1166 {
1167 NS_LOG_DEBUG("No other MSDU can be aggregated: maximum A-MSDU size (" << maxAmsduSize
1168 << ") reached ");
1169 return false;
1170 }
1171
1172 const WifiTxParameters::PsduInfo* info = txParams.GetPsduInfo(msdu->GetHeader().GetAddr1());
1173 NS_ASSERT(info);
1174
1175 if (info->ampduSize > 0)
1176 {
1177 // the A-MSDU being built is aggregated to other MPDUs in an A-MPDU.
1178 // Check that the limit on A-MPDU size is met.
1179 if (!IsWithinAmpduSizeLimit(ret.second, receiver, tid, modulation))
1180 {
1181 return false;
1182 }
1183 }
1184
1185 return IsWithinSizeAndTimeLimits(ret.second, receiver, txParams, ppduDurationLimit);
1186}
1187
1188void
1190{
1191 NS_LOG_FUNCTION(this << *psdu << txVector);
1192
1194
1195 bool resetCw;
1196 MissedBlockAck(psdu, txVector, resetCw);
1197
1199
1200 if (resetCw)
1201 {
1203 }
1204 else
1205 {
1207 }
1208
1209 m_psdu = nullptr;
1211}
1212
1213void
1215 const WifiTxVector& txVector,
1216 bool& resetCw)
1217{
1218 NS_LOG_FUNCTION(this << psdu << txVector << resetCw);
1219
1220 Mac48Address recipient = psdu->GetAddr1();
1221 bool isBar;
1222 uint8_t tid;
1223
1224 if (psdu->GetNMpdus() == 1 && psdu->GetHeader(0).IsBlockAckReq())
1225 {
1226 isBar = true;
1227 CtrlBAckRequestHeader baReqHdr;
1228 psdu->GetPayload(0)->PeekHeader(baReqHdr);
1229 tid = baReqHdr.GetTidInfo();
1230 }
1231 else
1232 {
1233 isBar = false;
1235 ->ReportAmpduTxStatus(recipient, 0, psdu->GetNMpdus(), 0, 0, txVector);
1236 std::set<uint8_t> tids = psdu->GetTids();
1237 NS_ABORT_MSG_IF(tids.size() > 1, "Multi-TID A-MPDUs not handled here");
1238 NS_ASSERT(!tids.empty());
1239 tid = *tids.begin();
1240 }
1241
1242 Ptr<QosTxop> edca = m_mac->GetQosTxop(tid);
1243
1244 if (edca->UseExplicitBarAfterMissedBlockAck() || isBar)
1245 {
1246 // we have to send a BlockAckReq, if needed
1247 if (GetBaManager(tid)->NeedBarRetransmission(tid, recipient))
1248 {
1249 NS_LOG_DEBUG("Missed Block Ack, transmit a BlockAckReq");
1250 if (isBar)
1251 {
1252 psdu->GetHeader(0).SetRetry();
1253 edca->ScheduleBar(*psdu->begin());
1254 }
1255 else
1256 {
1257 // missed block ack after data frame with Implicit BAR Ack policy
1258 edca->ScheduleBar(edca->PrepareBlockAckRequest(recipient, tid));
1259 }
1260 resetCw = false;
1261 }
1262 else
1263 {
1264 NS_LOG_DEBUG("Missed Block Ack, do not transmit a BlockAckReq");
1265 // if a BA agreement exists, we can get here if there is no outstanding
1266 // MPDU whose lifetime has not expired yet.
1268 if (GetBaManager(tid)->ExistsAgreementInState(recipient,
1269 tid,
1271 {
1272 // schedule a BlockAckRequest with skipIfNoDataQueued set to true, so that the
1273 // BlockAckRequest is only sent if there are data frames queued for this recipient.
1274 edca->ScheduleBar(edca->PrepareBlockAckRequest(recipient, tid), true);
1275 }
1276 resetCw = true;
1277 }
1278 }
1279 else
1280 {
1281 // we have to retransmit the data frames, if needed
1282 if (!GetWifiRemoteStationManager()->NeedRetransmission(*psdu->begin()))
1283 {
1284 NS_LOG_DEBUG("Missed Block Ack, do not retransmit the data frames");
1286 for (const auto& mpdu : *PeekPointer(psdu))
1287 {
1289 DequeueMpdu(mpdu);
1290 }
1291 resetCw = true;
1292 }
1293 else
1294 {
1295 NS_LOG_DEBUG("Missed Block Ack, retransmit data frames");
1296 GetBaManager(tid)->NotifyMissedBlockAck(recipient, tid);
1297 resetCw = false;
1298 }
1299 }
1300}
1301
1302void
1304 Time durationId,
1305 WifiTxVector& blockAckTxVector,
1306 double rxSnr)
1307{
1308 NS_LOG_FUNCTION(this << durationId << blockAckTxVector << rxSnr);
1309
1310 WifiMacHeader hdr;
1312 hdr.SetAddr1(agreement.GetPeer());
1313 hdr.SetAddr2(m_self);
1314 hdr.SetDsNotFrom();
1315 hdr.SetDsNotTo();
1316
1317 CtrlBAckResponseHeader blockAck;
1318 blockAck.SetType(agreement.GetBlockAckType());
1319 blockAck.SetTidInfo(agreement.GetTid());
1320 agreement.FillBlockAckBitmap(&blockAck);
1321
1322 Ptr<Packet> packet = Create<Packet>();
1323 packet->AddHeader(blockAck);
1324 Ptr<WifiPsdu> psdu = GetWifiPsdu(Create<WifiMpdu>(packet, hdr), blockAckTxVector);
1325
1326 // 802.11-2016, Section 9.2.5.7: In a BlockAck frame transmitted in response
1327 // to a BlockAckReq frame or transmitted in response to a frame containing an
1328 // implicit block ack request, the Duration/ID field is set to the value obtained
1329 // from the Duration/ ID field of the frame that elicited the response minus the
1330 // time, in microseconds between the end of the PPDU carrying the frame that
1331 // elicited the response and the end of the PPDU carrying the BlockAck frame.
1332 Time baDurationId = durationId - m_phy->GetSifs() -
1333 m_phy->CalculateTxDuration(psdu, blockAckTxVector, m_phy->GetPhyBand());
1334 // The TXOP holder may exceed the TXOP limit in some situations (Sec. 10.22.2.8 of 802.11-2016)
1335 if (baDurationId.IsStrictlyNegative())
1336 {
1337 baDurationId = Seconds(0);
1338 }
1339 psdu->GetHeader(0).SetDuration(baDurationId);
1340
1341 SnrTag tag;
1342 tag.Set(rxSnr);
1343 psdu->GetPayload(0)->AddPacketTag(tag);
1344
1345 ForwardPsduDown(psdu, blockAckTxVector);
1346}
1347
1348bool
1350{
1351 return (m_agreements.find({originator, tid}) != m_agreements.end());
1352}
1353
1356{
1357 auto it = m_agreements.find({originator, tid});
1358 NS_ABORT_MSG_IF(it == m_agreements.end(), "No established Block Ack agreement");
1359 return it->second.GetBlockAckType();
1360}
1361
1362void
1364 RxSignalInfo rxSignalInfo,
1365 const WifiTxVector& txVector,
1366 bool inAmpdu)
1367{
1368 // The received MPDU is either broadcast or addressed to this station
1369 NS_ASSERT(mpdu->GetHeader().GetAddr1().IsGroup() || mpdu->GetHeader().GetAddr1() == m_self);
1370
1371 double rxSnr = rxSignalInfo.snr;
1372 const WifiMacHeader& hdr = mpdu->GetHeader();
1373
1374 if (hdr.IsCtl())
1375 {
1376 if (hdr.IsCts() && m_txTimer.IsRunning() &&
1378 {
1379 NS_ABORT_MSG_IF(inAmpdu, "Received CTS as part of an A-MPDU");
1380 NS_ASSERT(hdr.GetAddr1() == m_self);
1381
1382 Mac48Address sender = m_psdu->GetAddr1();
1383 NS_LOG_DEBUG("Received CTS from=" << sender);
1384
1385 SnrTag tag;
1386 mpdu->GetPacket()->PeekPacketTag(tag);
1387 GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
1389 rxSnr,
1390 txVector.GetMode(),
1391 tag.Get());
1392
1393 m_txTimer.Cancel();
1396 }
1397 else if (hdr.IsBlockAck() && m_txTimer.IsRunning() &&
1399 {
1400 Mac48Address sender = hdr.GetAddr2();
1401 NS_LOG_DEBUG("Received BlockAck from=" << sender);
1402
1403 SnrTag tag;
1404 mpdu->GetPacket()->PeekPacketTag(tag);
1405
1406 // notify the Block Ack Manager
1407 CtrlBAckResponseHeader blockAck;
1408 mpdu->GetPacket()->PeekHeader(blockAck);
1409 uint8_t tid = blockAck.GetTidInfo();
1410 std::pair<uint16_t, uint16_t> ret =
1411 GetBaManager(tid)->NotifyGotBlockAck(blockAck, hdr.GetAddr2(), {tid});
1413 ret.first,
1414 ret.second,
1415 rxSnr,
1416 tag.Get(),
1418
1419 // cancel the timer
1420 m_txTimer.Cancel();
1422
1423 // Reset the CW
1425
1426 m_psdu = nullptr;
1428 }
1429 else if (hdr.IsBlockAckReq())
1430 {
1431 NS_ASSERT(hdr.GetAddr1() == m_self);
1432 NS_ABORT_MSG_IF(inAmpdu, "BlockAckReq in A-MPDU is not supported");
1433
1434 Mac48Address sender = hdr.GetAddr2();
1435 NS_LOG_DEBUG("Received BlockAckReq from=" << sender);
1436
1437 CtrlBAckRequestHeader blockAckReq;
1438 mpdu->GetPacket()->PeekHeader(blockAckReq);
1439 NS_ABORT_MSG_IF(blockAckReq.IsMultiTid(), "Multi-TID BlockAckReq not supported");
1440 uint8_t tid = blockAckReq.GetTidInfo();
1441
1442 auto agreementIt = m_agreements.find({sender, tid});
1443
1444 if (agreementIt == m_agreements.end())
1445 {
1446 NS_LOG_DEBUG("There's not a valid agreement for this BlockAckReq");
1447 return;
1448 }
1449
1450 agreementIt->second.NotifyReceivedBar(blockAckReq.GetStartingSequence());
1451
1452 NS_LOG_DEBUG("Schedule Block Ack");
1454 m_phy->GetSifs(),
1456 this,
1457 agreementIt->second,
1458 hdr.GetDuration(),
1459 GetWifiRemoteStationManager()->GetBlockAckTxVector(sender, txVector),
1460 rxSnr);
1461 }
1462 else
1463 {
1464 // the received control frame cannot be handled here
1465 QosFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
1466 }
1467 return;
1468 }
1469
1470 if (hdr.IsQosData() && hdr.HasData() && hdr.GetAddr1() == m_self)
1471 {
1472 uint8_t tid = hdr.GetQosTid();
1473
1474 auto agreementIt = m_agreements.find({hdr.GetAddr2(), tid});
1475 if (agreementIt != m_agreements.end())
1476 {
1477 // a Block Ack agreement has been established
1478 NS_LOG_DEBUG("Received from=" << hdr.GetAddr2() << " (" << *mpdu << ")");
1479
1480 agreementIt->second.NotifyReceivedMpdu(mpdu);
1481
1482 if (!inAmpdu && hdr.GetQosAckPolicy() == WifiMacHeader::NORMAL_ACK)
1483 {
1484 NS_LOG_DEBUG("Schedule Normal Ack");
1487 this,
1488 hdr,
1489 txVector,
1490 rxSnr);
1491 }
1492 return;
1493 }
1494 // We let the QosFrameExchangeManager handle QoS data frame not belonging
1495 // to a Block Ack agreement
1496 }
1497
1498 QosFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
1499}
1500
1501void
1503 const RxSignalInfo& rxSignalInfo,
1504 const WifiTxVector& txVector,
1505 const std::vector<bool>& perMpduStatus)
1506{
1507 std::set<uint8_t> tids = psdu->GetTids();
1508
1509 // Multi-TID A-MPDUs are not supported yet
1510 if (tids.size() == 1)
1511 {
1512 uint8_t tid = *tids.begin();
1513 WifiMacHeader::QosAckPolicy ackPolicy = psdu->GetAckPolicyForTid(tid);
1514 NS_ASSERT(psdu->GetNMpdus() > 1);
1515
1516 if (ackPolicy == WifiMacHeader::NORMAL_ACK)
1517 {
1518 // Normal Ack or Implicit Block Ack Request
1519 NS_LOG_DEBUG("Schedule Block Ack");
1520 auto agreementIt = m_agreements.find({psdu->GetAddr2(), tid});
1521 NS_ASSERT(agreementIt != m_agreements.end());
1522
1524 m_phy->GetSifs(),
1526 this,
1527 agreementIt->second,
1528 psdu->GetDuration(),
1529 GetWifiRemoteStationManager()->GetBlockAckTxVector(psdu->GetAddr2(), txVector),
1530 rxSignalInfo.snr);
1531 }
1532 }
1533}
1534
1535} // namespace ns3
#define max(a, b)
Definition: 80211b.c:43
uint16_t GetTimeout() const
Return the timeout.
void SetImmediateBlockAck()
Set block ack policy to immediate Ack.
BlockAckType GetBlockAckType() const
Get the type of the Block Acks sent by the recipient of this agreement.
EventId m_inactivityEvent
inactivity event
void SetDelayedBlockAck()
Set block ack policy to delayed Ack.
uint8_t GetTid() const
Return the Traffic ID (TID).
static std::size_t GetDistance(uint16_t seqNumber, uint16_t startingSeqNumber)
Get the distance between the given starting sequence number and the given sequence number.
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:51
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.
Headers for BlockAck response.
Definition: ctrl-headers.h:202
uint8_t GetTidInfo(std::size_t index=0) const
For Block Ack variants other than Multi-STA Block Ack, get the TID_INFO subfield of the BA Control fi...
void SetTidInfo(uint8_t tid, std::size_t index=0)
For Block Ack variants other than Multi-STA Block Ack, set the TID_INFO subfield of the BA Control fi...
void SetType(BlockAckType type)
Set the block ack type.
void DoCtsTimeout(Ptr< WifiPsdu > psdu)
Take required actions when the CTS timer fired after sending an RTS to protect the given PSDU expires...
uint8_t m_linkId
the ID of the link this object is associated with
Ptr< WifiMac > m_mac
the MAC layer on this station
virtual void SetWifiMac(const Ptr< WifiMac > mac)
Set the MAC layer to use.
void SendMpduWithProtection(Ptr< WifiMpdu > mpdu, WifiTxParameters &txParams)
Send an MPDU with the given TX parameters (with the specified protection).
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager() const
void UpdateTxDuration(Mac48Address receiver, WifiTxParameters &txParams) const
Update the TX duration field of the given TX parameters after that the PSDU addressed to the given re...
virtual void CalculateAcknowledgmentTime(WifiAcknowledgment *acknowledgment) const
Calculate the time required to acknowledge a frame according to the given acknowledgment method.
Ptr< MacTxMiddle > m_txMiddle
the MAC TX Middle on this station
void SendNormalAck(const WifiMacHeader &hdr, const WifiTxVector &dataTxVector, double dataSnr)
Send Normal Ack.
Mac48Address m_self
the MAC address of this device
uint16_t m_allowedWidth
the allowed width in MHz for the current transmission
virtual void NotifyPacketDiscarded(Ptr< const WifiMpdu > mpdu)
Pass the given MPDU, discarded because of the max retry limit was reached, to the MPDU dropped callba...
WifiTxTimer m_txTimer
the timer set upon frame transmission
virtual void RetransmitMpduAfterMissedAck(Ptr< WifiMpdu > mpdu) const
Retransmit an MPDU that was not acknowledged.
void SendRts(const WifiTxParameters &txParams)
Send RTS to begin RTS-CTS-Data-Ack transaction.
virtual void NotifyReceivedNormalAck(Ptr< WifiMpdu > mpdu)
Notify other components that an MPDU was acknowledged.
void SendCtsToSelf(const WifiTxParameters &txParams)
Send CTS for a CTS-to-self mechanism.
virtual void CtsTimeout(Ptr< WifiMpdu > rts, const WifiTxVector &txVector)
Called when the CTS timeout expires.
virtual void CalculateProtectionTime(WifiProtection *protection) const
Calculate the time required to protect a frame according to the given protection method.
Ptr< WifiAckManager > GetAckManager() const
Get the Acknowledgment Manager used by this node.
virtual void DequeueMpdu(Ptr< const WifiMpdu > mpdu)
Dequeue the given MPDU from the queue in which it is stored.
Ptr< WifiProtectionManager > GetProtectionManager() const
Get the Protection Manager used by this node.
Ptr< MacRxMiddle > m_rxMiddle
the MAC RX Middle on this station
Ptr< WifiPhy > m_phy
the PHY layer on this station
Mac48Address m_bssid
BSSID address (Mac48Address)
virtual void ReleaseSequenceNumber(Ptr< WifiMpdu > mpdu) const
Make the sequence number of the given MPDU available again if the MPDU has never been transmitted.
Ptr< ChannelAccessManager > m_channelAccessManager
the channel access manager
HtFrameExchangeManager handles the frame exchange sequences for HT stations.
Ptr< MpduAggregator > m_mpduAggregator
A-MPDU aggregator.
void ReceiveMpdu(Ptr< const WifiMpdu > mpdu, RxSignalInfo rxSignalInfo, const WifiTxVector &txVector, bool inAmpdu) override
This method handles the reception of an MPDU (possibly included in an A-MPDU)
void SendAddBaRequest(Mac48Address recipient, uint8_t tid, uint16_t startingSeq, uint16_t timeout, bool immediateBAck)
Sends an ADDBA Request to establish a block ack agreement with STA addressed by recipient for TID tid...
void SendDelbaFrame(Mac48Address addr, uint8_t tid, bool byOriginator)
Sends DELBA frame to cancel a block ack agreement with STA addressed by addr for TID tid.
std::map< AgreementKey, Ptr< WifiMpdu > > m_pendingAddBaResp
pending ADDBA_RESPONSE frames indexed by agreement key
void SendAddBaResponse(const MgtAddBaRequestHeader *reqHdr, Mac48Address originator)
This method can be called to accept a received ADDBA Request.
virtual bool SendMpduFromBaManager(Ptr< QosTxop > edca, Time availableTime, bool initialFrame)
If the Block Ack Manager associated with the given EDCA has a BlockAckReq frame to transmit (the dura...
void CtsTimeout(Ptr< WifiMpdu > rts, const WifiTxVector &txVector) override
Called when the CTS timeout expires.
void DestroyBlockAckAgreement(Mac48Address originator, uint8_t tid)
Destroy a Block Ack agreement.
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.
virtual Time GetPsduDurationId(Time txDuration, const WifiTxParameters &txParams) const
Compute how to set the Duration/ID field of PSDUs that do not include fragments.
void CreateBlockAckAgreement(const MgtAddBaResponseHeader *respHdr, Mac48Address originator, uint16_t startingSeq)
virtual bool NeedSetupBlockAck(Mac48Address recipient, uint8_t tid)
A Block Ack agreement needs to be established with the given recipient for the given TID if it does n...
void TransmissionSucceeded() override
Take necessary actions upon a transmission success.
void ReleaseSequenceNumber(Ptr< WifiMpdu > mpdu) const override
Make the sequence number of the given MPDU available again if the MPDU has never been transmitted.
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.
RecipientBlockAckAgreementMap m_pendingAgreements
pending Block Ack agreements (waiting for Ack in response to ADDBA_RESPONSE)
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...
bool GetBaAgreementEstablished(Mac48Address originator, uint8_t tid) const
Return true if a Block Ack agreement has been established with the given originator for the given TID...
void NotifyReceivedNormalAck(Ptr< WifiMpdu > mpdu) override
Notify other components that an MPDU was acknowledged.
void EndReceiveAmpdu(Ptr< const WifiPsdu > psdu, const RxSignalInfo &rxSignalInfo, const WifiTxVector &txVector, const std::vector< bool > &perMpduStatus) override
This method is called when the reception of an A-MPDU including multiple MPDUs is completed.
void RetransmitMpduAfterMissedAck(Ptr< WifiMpdu > mpdu) const override
Retransmit an MPDU that was not acknowledged.
void DoDispose() override
Destructor implementation.
static TypeId GetTypeId()
Get the type ID.
bool StartFrameExchange(Ptr< QosTxop > edca, Time availableTime, bool initialFrame) override
Start a frame exchange (including protection frames and acknowledgment frames as needed) that fits wi...
WifiTxParameters m_txParams
the TX parameters for the current frame
bool IsWithinLimitsIfAddMpdu(Ptr< const WifiMpdu > mpdu, const WifiTxParameters &txParams, Time ppduDurationLimit) const override
Check if the PSDU obtained by aggregating the given MPDU to the PSDU specified by the given TX parame...
void SendPsdu()
Send the current PSDU, which can be acknowledged by a BlockAck frame or followed by a BlockAckReq fra...
virtual uint16_t GetSupportedBaBufferSize() const
Get the maximum supported buffer size for a Block Ack agreement.
virtual bool TryAggregateMsdu(Ptr< const WifiMpdu > msdu, WifiTxParameters &txParams, Time availableTime) const
Check if aggregating an MSDU to the current MPDU (as specified by the given TX parameters) does not v...
virtual void NotifyTxToEdca(Ptr< const WifiPsdu > psdu) const
Notify the transmission of the given PSDU to the EDCAF associated with the AC the PSDU belongs to.
virtual bool SendDataFrame(Ptr< WifiMpdu > peekedItem, Time availableTime, bool initialFrame)
Given a non-broadcast QoS data frame, prepare the PSDU to transmit by attempting A-MSDU and A-MPDU ag...
void NotifyPacketDiscarded(Ptr< const WifiMpdu > mpdu) override
Pass the given MPDU, discarded because of the max retry limit was reached, to the MPDU dropped callba...
RecipientBlockAckAgreementMap m_agreements
Block Ack agreements.
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.
BlockAckType GetBlockAckType(Mac48Address originator, uint8_t tid) const
Get the type of BlockAck frames sent to the given originator.
void DequeuePsdu(Ptr< const WifiPsdu > psdu)
Dequeue the MPDUs of the given PSDU from the queue in which they are stored.
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:1476
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:1607
void SetTid(uint8_t tid)
Set Traffic ID (TID).
uint16_t GetBufferSize() const
Return the buffer size.
bool IsAmsduSupported() const
Return whether A-MSDU capability is supported.
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).
bool IsImmediateBlockAck() const
Return whether the Block Ack policy is immediate Block Ack.
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:1726
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.
uint32_t RemoveHeader(Header &header)
Deserialize and remove the header from the internal buffer.
Definition: packet.cc:294
void AddHeader(const Header &header)
Add header to this packet.
Definition: packet.cc:268
void AddPacketTag(const Tag &tag) const
Add a packet tag.
Definition: packet.cc:979
uint32_t PeekHeader(Header &header) const
Deserialize but does not remove the header from the internal buffer.
Definition: packet.cc:305
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
bool StartTransmission(Ptr< Txop > edca, uint16_t allowedWidth) override
Request the FrameExchangeManager to start a frame exchange sequence.
void TransmissionSucceeded() override
Take necessary actions upon a transmission success.
bool m_setQosQueueSize
whether to set the Queue Size subfield of the QoS Control field of QoS data frames
virtual bool IsWithinSizeAndTimeLimits(uint32_t ppduPayloadSize, Mac48Address receiver, const WifiTxParameters &txParams, Time ppduDurationLimit) const
Check whether the transmission time of the frame being built (as described by the given TX parameters...
void DoDispose() override
Destructor implementation.
Ptr< BlockAckManager > GetBaManager()
Get the Block Ack Manager associated with this QosTxop.
Definition: qos-txop.cc:255
bool UseExplicitBarAfterMissedBlockAck() const
Return true if an explicit BlockAckRequest is sent after a missed BlockAck.
Definition: qos-txop.cc:309
Time GetAddBaResponseTimeout() const
Get the timeout for ADDBA response.
Definition: qos-txop.cc:722
void AddBaResponseTimeout(Mac48Address recipient, uint8_t tid)
Callback when ADDBA response is not received after timeout.
Definition: qos-txop.cc:680
Ptr< const WifiMpdu > PrepareBlockAckRequest(Mac48Address recipient, uint8_t tid) const
Definition: qos-txop.cc:281
void ScheduleBar(Ptr< const WifiMpdu > bar, bool skipIfNoDataQueued=false)
Definition: qos-txop.cc:303
uint8_t GetBlockAckThreshold() const
Return the current threshold for block ack mechanism.
Definition: qos-txop.cc:667
uint16_t GetBlockAckInactivityTimeout() const
Get the BlockAck inactivity timeout.
Definition: qos-txop.cc:674
virtual Time GetRemainingTxop(uint8_t linkId) const
Return the remaining duration in the current TXOP on the given link.
Definition: qos-txop.cc:581
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:148
bool GetBaAgreementEstablished(Mac48Address address, uint8_t tid) const
Definition: qos-txop.cc:261
void ResetBa(Mac48Address recipient, uint8_t tid)
Reset BA agreement after BA negotiation failed.
Definition: qos-txop.cc:698
Time GetFailedAddBaTimeout() const
Get the timeout for failed BA agreement.
Definition: qos-txop.cc:735
Ptr< WifiMpdu > PeekNextMpdu(uint8_t linkId, uint8_t tid=8, Mac48Address recipient=Mac48Address::GetBroadcast(), Ptr< WifiMpdu > item=nullptr)
Peek the next frame to transmit on the given link to the given receiver and of the given TID from the...
Definition: qos-txop.cc:368
Ptr< WifiMpdu > GetNextMpdu(uint8_t linkId, Ptr< WifiMpdu > peekedItem, WifiTxParameters &txParams, Time availableTime, bool initialFrame)
Prepare the frame to transmit on the given link starting from the MPDU that has been previously peeke...
Definition: qos-txop.cc:454
void CompleteMpduTx(Ptr< WifiMpdu > mpdu)
Stores an MPDU (part of an A-MPDU) in block ack agreement (i.e.
Definition: qos-txop.cc:641
uint16_t GetBaStartingSequence(Mac48Address address, uint8_t tid) const
Definition: qos-txop.cc:275
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 ...
void SetMacRxMiddle(const Ptr< MacRxMiddle > rxMiddle)
Set the MAC RX Middle to use.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:568
Introspection did not find any typical Config paths.
Definition: snr-tag.h:35
void Set(double snr)
Set the SNR to the given value.
Definition: snr-tag.cc:84
double Get() const
Return the SNR value.
Definition: snr-tag.cc:90
Status code for association response.
Definition: status-code.h:32
void SetSuccess()
Set success bit to 0 (success).
Definition: status-code.cc:30
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
static Time Min()
Minimum representable Time Not to be confused with Min(Time,Time).
Definition: nstime.h:286
bool IsStrictlyNegative() const
Exactly equivalent to t < 0.
Definition: nstime.h:341
bool IsZero() const
Exactly equivalent to t == 0.
Definition: nstime.h:314
Time GetTxopLimit() const
Return the TXOP limit.
Definition: txop.cc:473
void UpdateFailedCw(uint8_t linkId)
Update the value of the CW variable for the given link to take into account a transmission failure.
Definition: txop.cc:300
Ptr< WifiMacQueue > GetWifiMacQueue() const
Return the packet queue associated with this Txop.
Definition: txop.cc:220
void ResetCw(uint8_t linkId)
Update the value of the CW variable for the given link to take into account a transmission success or...
Definition: txop.cc:291
a unique identifier for an interface.
Definition: type-id.h:60
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:935
static void SetQosAckPolicy(Ptr< WifiMpdu > item, const WifiAcknowledgment *acknowledgment)
Set the QoS Ack policy for the given MPDU, which must be a QoS data frame.
See IEEE 802.11 chapter 7.3.1.11 Header format: | category: 1 | action value: 1 |.
Definition: mgt-headers.h:1244
CategoryValue GetCategory()
Return the category value.
ActionValue GetAction()
Return the action value.
void SetAction(CategoryValue type, ActionValue action)
Set action for this Action header.
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.
void SetRetry()
Set the Retry bit in the Frame Control field.
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 SetDuration(Time duration)
Set the Duration/ID field with the given duration (Time object).
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.
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:1635
Time GetSlot() const
Return the slot duration for this PHY.
Definition: wifi-phy.cc:740
Time GetSifs() const
Return the Short Interframe Space (SIFS) for this PHY.
Definition: wifi-phy.cc:728
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition: wifi-phy.cc:1422
WifiPhyBand GetPhyBand() const
Get the configured Wi-Fi band.
Definition: wifi-phy.cc:950
static Time CalculatePhyPreambleAndHeaderDuration(const WifiTxVector &txVector)
Definition: wifi-phy.cc:1415
std::set< uint8_t > GetTids() const
Get the set of TIDs of the QoS Data frames included in the PSDU.
Definition: wifi-psdu.cc:168
const WifiMacHeader & GetHeader(std::size_t i) const
Get the header of the i-th MPDU.
Definition: wifi-psdu.cc:269
Time GetDuration() const
Get the duration from the Duration/ID field, which is common to all the MPDUs.
Definition: wifi-psdu.cc:143
std::vector< Ptr< WifiMpdu > >::const_iterator begin() const
Return a const iterator to the first MPDU.
Definition: wifi-psdu.cc:323
Mac48Address GetAddr2() const
Get the Transmitter Address (TA), which is common to all the MPDUs.
Definition: wifi-psdu.cc:128
uint32_t GetSize() const
Return the size of the PSDU in bytes.
Definition: wifi-psdu.cc:263
Ptr< const Packet > GetPayload(std::size_t i) const
Get the payload of the i-th MPDU.
Definition: wifi-psdu.cc:281
Mac48Address GetAddr1() const
Get the Receiver Address (RA), which is common to all the MPDUs.
Definition: wifi-psdu.cc:113
bool IsAggregate() const
Return true if the PSDU is an S-MPDU or A-MPDU.
Definition: wifi-psdu.cc:83
void SetDuration(Time duration)
Set the Duration/ID field on all the MPDUs.
Definition: wifi-psdu.cc:158
std::size_t GetNMpdus() const
Return the number of MPDUs constituting the PSDU.
Definition: wifi-psdu.cc:317
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:182
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.
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 GetVhtSupported() const
Return whether the device has VHT capability support enabled.
WifiTxVector GetDataTxVector(const WifiMacHeader &header, uint16_t allowedWidth)
This class stores the TX parameters (TX vector, protection mechanism, acknowledgment mechanism,...
uint32_t GetSizeIfAddMpdu(Ptr< const WifiMpdu > mpdu) const
Get the size in bytes of the frame in case the given MPDU is added.
std::pair< uint32_t, uint32_t > GetSizeIfAggregateMsdu(Ptr< const WifiMpdu > msdu) const
Get the size in bytes of the frame in case the given MSDU is aggregated.
std::unique_ptr< WifiProtection > m_protection
protection method
uint32_t GetSize(Mac48Address receiver) const
Get the size in bytes of the (A-)MPDU addressed to the given receiver.
std::unique_ptr< WifiAcknowledgment > m_acknowledgment
acknowledgment method
const PsduInfo * GetPsduInfo(Mac48Address receiver) const
Get a pointer to the information about the PSDU addressed to the given receiver, if present,...
WifiTxVector m_txVector
TXVECTOR of the frame being prepared.
void AggregateMsdu(Ptr< const WifiMpdu > msdu)
Record that an MSDU is being aggregated to the last MPDU added to the frame that hase the same receiv...
void Clear()
Reset the TX parameters.
bool IsRunning() const
Return true if the timer is running.
void Cancel()
Cancel the timer.
void Set(Reason reason, const Time &delay, MEM mem_ptr, OBJ obj, Args... args)
This method is called when a frame soliciting a response is transmitted.
Reason GetReason() const
Get the reason why the timer was started.
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
WifiMode GetMode(uint16_t staId=SU_STA_ID) const
If this TX vector is associated with an SU PPDU, return the selected payload transmission mode.
void SetAggregation(bool aggregation)
Sets if PSDU contains A-MPDU.
WifiModulationClass GetModulationClass() const
Get the modulation class specified by this TXVECTOR.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:86
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition: abort.h:49
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
#define NS_ABORT_IF(cond)
Abnormal program termination if a condition is true.
Definition: abort.h:76
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:45
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1362
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1338
uint8_t GetTid(Ptr< const Packet > packet, const WifiMacHeader hdr)
This function is useful to get traffic id of different packet types.
Definition: qos-utils.cc:193
WifiModulationClass
This enumeration defines the modulation classes per (Table 10-6 "Modulation classes"; IEEE 802....
@ WIFI_MOD_CLASS_HT
HT (Clause 19)
void(* Time)(Time oldValue, Time newValue)
TracedValue callback signature for Time.
Definition: nstime.h:850
Every class exported by the ns3 library is enclosed in the ns3 namespace.
U * PeekPointer(const Ptr< U > &p)
Definition: ptr.h:488
@ STA
Definition: wifi-mac.h:60
std::tuple< WifiContainerQueueType, Mac48Address, uint8_t > WifiContainerQueueId
Tuple (queue 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
@ WIFI_QOSDATA_UNICAST_QUEUE
Ptr< T > Copy(Ptr< T > object)
Return a deep copy of a Ptr.
Definition: ptr.h:649
uint32_t GetBlockAckSize(BlockAckType type)
Return the total BlockAck size (including FCS trailer).
Definition: wifi-utils.cc:66
value
Definition: second.py:41
mac
Definition: third.py:85
ns3::Time timeout
The different BlockAck variants.
RxSignalInfo structure containing info on the received signal.
Definition: phy-entity.h:70
double snr
SNR in linear scale.
Definition: phy-entity.h:71
WifiAcknowledgment is an abstract base struct.
Time acknowledgmentTime
time required by the acknowledgment method
const Method method
acknowledgment method
WifiBarBlockAck specifies that a BlockAckReq is sent to solicit a Block Ack response.
BlockAckType baType
BlockAck type.
WifiTxVector blockAckTxVector
BlockAck TXVECTOR.
WifiTxVector blockAckReqTxVector
BlockAckReq TXVECTOR.
BlockAckReqType barType
BlockAckReq type.
WifiBlockAck specifies that acknowledgment via Block Ack is required.
WifiTxVector blockAckTxVector
BlockAck TXVECTOR.
BlockAckType baType
BlockAck type.
WifiNoProtection specifies that no protection method is used.
information about the frame being prepared for a specific receiver
std::map< uint8_t, std::set< uint16_t > > seqNumbers
set of the sequence numbers of the MPDUs added for each TID
uint32_t ampduSize
the size in bytes of the A-MPDU if multiple MPDUs have been added, and zero otherwise
typedef for union of different ActionValues
Definition: mgt-headers.h:1409
BlockAckActionValue blockAck
block ack
Definition: mgt-headers.h:1411