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