A Discrete-Event Network Simulator
API
he-frame-exchange-manager.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2020 Universita' degli Studi di Napoli Federico II
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Author: Stefano Avallone <stavallo@unina.it>
19  */
20 
21 #include "ns3/log.h"
22 #include "ns3/abort.h"
24 #include "he-configuration.h"
25 #include "ns3/recipient-block-ack-agreement.h"
26 #include "ns3/ap-wifi-mac.h"
27 #include "ns3/sta-wifi-mac.h"
28 #include "multi-user-scheduler.h"
29 #include "ns3/snr-tag.h"
30 #include "he-phy.h"
31 #include <algorithm>
32 #include <functional>
33 
34 #undef NS_LOG_APPEND_CONTEXT
35 #define NS_LOG_APPEND_CONTEXT std::clog << "[mac=" << m_self << "] "
36 
37 namespace ns3 {
38 
39 NS_LOG_COMPONENT_DEFINE ("HeFrameExchangeManager");
40 
41 NS_OBJECT_ENSURE_REGISTERED (HeFrameExchangeManager);
42 
43 TypeId
45 {
46  static TypeId tid = TypeId ("ns3::HeFrameExchangeManager")
48  .AddConstructor<HeFrameExchangeManager> ()
49  .SetGroupName ("Wifi")
50  ;
51  return tid;
52 }
53 
55  : m_triggerFrameInAmpdu (false)
56 {
57  NS_LOG_FUNCTION (this);
58 }
59 
61 {
63 }
64 
65 uint16_t
67 {
68  NS_ASSERT (m_mac->GetHeConfiguration () != 0);
69  if (m_mac->GetHeConfiguration ()->GetMpduBufferSize () > 64)
70  {
71  return 256;
72  }
73  return 64;
74 }
75 
76 void
78 {
79  m_apMac = DynamicCast<ApWifiMac> (mac);
80  m_staMac = DynamicCast<StaWifiMac> (mac);
82 }
83 
84 void
86 {
87  NS_LOG_FUNCTION (this);
88  m_apMac = 0;
89  m_staMac = 0;
90  m_psduMap.clear ();
91  m_txParams.Clear ();
92  m_muScheduler = 0;
95 }
96 
97 void
99 {
100  NS_ASSERT (m_mac);
101  NS_ABORT_MSG_IF (m_apMac == 0,
102  "A Multi-User Scheduler can only be aggregated to an AP");
103  NS_ABORT_MSG_IF (m_apMac->GetHeConfiguration () == 0,
104  "A Multi-User Scheduler can only be aggregated to an HE AP");
105  m_muScheduler = muScheduler;
106 }
107 
108 bool
109 HeFrameExchangeManager::StartFrameExchange (Ptr<QosTxop> edca, Time availableTime, bool initialFrame)
110 {
111  NS_LOG_FUNCTION (this << edca << availableTime << initialFrame);
112 
115 
116  /*
117  * We consult the Multi-user Scheduler (if available) to know the type of transmission to make if:
118  * - there is no pending BlockAckReq to transmit
119  * - either the AC queue is empty (the scheduler might select an UL MU transmission)
120  * or the next frame in the AC queue is a non-broadcast QoS data frame addressed to
121  * a receiver with which a BA agreement has been already established
122  */
123  if (m_muScheduler != 0
124  && edca->GetBaManager ()->GetBar (false) == nullptr
125  && (mpdu == 0
126  || (mpdu->GetHeader ().IsQosData ()
127  && !mpdu->GetHeader ().GetAddr1 ().IsGroup ()
128  && edca->GetBaAgreementEstablished (mpdu->GetHeader ().GetAddr1 (), mpdu->GetHeader ().GetQosTid ()))))
129  {
130  txFormat = m_muScheduler->NotifyAccessGranted (edca, availableTime, initialFrame);
131  }
132 
133  if (txFormat == MultiUserScheduler::SU_TX)
134  {
135  return VhtFrameExchangeManager::StartFrameExchange (edca, availableTime, initialFrame);
136  }
137 
138  if (txFormat == MultiUserScheduler::DL_MU_TX)
139  {
140  if (m_muScheduler->GetDlMuInfo ().psduMap.empty ())
141  {
142  NS_LOG_DEBUG ("The Multi-user Scheduler returned DL_MU_TX with empty psduMap, do not transmit");
143  return false;
144  }
145 
146  SendPsduMapWithProtection (m_muScheduler->GetDlMuInfo ().psduMap,
147  m_muScheduler->GetDlMuInfo ().txParams);
148  return true;
149  }
150 
151  if (txFormat == MultiUserScheduler::UL_MU_TX)
152  {
153  if (m_muScheduler->GetUlMuInfo ().trigger == nullptr)
154  {
155  NS_LOG_DEBUG ("The Multi-user Scheduler returned UL_MU_TX with empty Trigger Frame, do not transmit");
156  return false;
157  }
158 
159  NS_ASSERT (m_muScheduler->GetUlMuInfo ().trigger->GetHeader ().IsTrigger ());
161  m_muScheduler->GetUlMuInfo ().txParams.m_txVector)}},
162  m_muScheduler->GetUlMuInfo ().txParams);
163  return true;
164  }
165 
166  return false;
167 }
168 
169 bool
170 HeFrameExchangeManager::SendMpduFromBaManager (Ptr<QosTxop> edca, Time availableTime, bool initialFrame)
171 {
172  NS_LOG_FUNCTION (this << edca << availableTime << initialFrame);
173 
174  // First, check if there is a BAR to be transmitted
175  Ptr<const WifiMacQueueItem> peekedItem = edca->GetBaManager ()->GetBar (false);
176 
177  if (peekedItem == 0)
178  {
179  NS_LOG_DEBUG ("Block Ack Manager returned no frame to send");
180  return false;
181  }
182 
183  if (peekedItem->GetHeader ().IsBlockAckReq ())
184  {
185  // BlockAckReq are handled by the HT FEM
186  return HtFrameExchangeManager::SendMpduFromBaManager (edca, availableTime, initialFrame);
187  }
188 
189  NS_ASSERT (peekedItem->GetHeader ().IsTrigger ());
190  m_triggerFrame = Copy (edca->GetBaManager ()->GetBar ());
191 
192  SendPsduMap ();
193  return true;
194 }
195 
196 void
198 {
199  NS_LOG_FUNCTION (this << &txParams);
200 
201  m_psduMap = std::move (psduMap);
202  m_txParams = std::move (txParams);
203 
204 #ifdef NS3_BUILD_PROFILE_DEBUG
205  // If protection is required, the MPDUs must be stored in some queue because
206  // they are not put back in a queue if the MU-RTS/CTS exchange fails
208  {
209  for (const auto& psdu : psduMap)
210  {
211  for (const auto& mpdu : *PeekPointer (psdu.second))
212  {
213  NS_ASSERT (mpdu->GetHeader ().IsCtl () || !mpdu->GetHeader ().HasData () || mpdu->IsQueued ());
214  }
215  }
216  }
217 #endif
218 
219  // Make sure that the acknowledgment time has been computed, so that SendMuRts()
220  // can reuse this value.
222 
223  if (m_txParams.m_acknowledgment->acknowledgmentTime == Time::Min ())
224  {
226  }
227 
228  // Set QoS Ack policy
229  for (auto& psdu : m_psduMap)
230  {
232  }
233 
235  {
236  SendPsduMap ();
237  }
238  else
239  {
240  NS_ABORT_MSG ("Unknown or prohibited protection type: " << m_txParams.m_protection.get ());
241  }
242 }
243 
246 {
247  auto it = std::find_if (psduMap.begin (), psduMap.end (),
248  [&to] (std::pair<uint16_t, Ptr<WifiPsdu>> psdu)
249  { return psdu.second->GetAddr1 () == to; });
250  if (it != psduMap.end ())
251  {
252  return it->second;
253  }
254  return nullptr;
255 }
256 
257 void
259 {
260  NS_LOG_FUNCTION (this);
261 
264 
265  WifiTxTimer::Reason timerType = WifiTxTimer::NOT_RUNNING; // no timer
266  WifiTxVector* responseTxVector = nullptr;
267  Ptr<WifiMacQueueItem> mpdu = nullptr;
268  Ptr<WifiPsdu> psdu = nullptr;
269  WifiTxVector txVector;
270 
271  // Compute the type of TX timer to set depending on the acknowledgment method
272 
273  /*
274  * Acknowledgment via a sequence of BlockAckReq and BlockAck frames
275  */
277  {
278  WifiDlMuBarBaSequence* acknowledgment = static_cast<WifiDlMuBarBaSequence*> (m_txParams.m_acknowledgment.get ());
279 
280  // schedule the transmission of required BlockAckReq frames
281  for (const auto& psdu : m_psduMap)
282  {
283  if (acknowledgment->stationsSendBlockAckReqTo.find (psdu.second->GetAddr1 ())
284  != acknowledgment->stationsSendBlockAckReqTo.end ())
285  {
286  // the receiver of this PSDU will receive a BlockAckReq
287  std::set<uint8_t> tids = psdu.second->GetTids ();
288  NS_ABORT_MSG_IF (tids.size () > 1, "Acknowledgment method incompatible with a Multi-TID A-MPDU");
289  uint8_t tid = *tids.begin ();
290 
291  NS_ASSERT (m_edca != 0);
292  m_edca->ScheduleBar (m_edca->PrepareBlockAckRequest (psdu.second->GetAddr1 (), tid));
293  }
294  }
295 
296  if (!acknowledgment->stationsReplyingWithNormalAck.empty ())
297  {
298  // a station will reply immediately with a Normal Ack
300  responseTxVector = &acknowledgment->stationsReplyingWithNormalAck.begin ()->second.ackTxVector;
301  psdu = GetPsduTo (acknowledgment->stationsReplyingWithNormalAck.begin ()->first, m_psduMap);
302  NS_ASSERT (psdu->GetNMpdus () == 1);
303  mpdu = *psdu->begin ();
304  }
305  else if (!acknowledgment->stationsReplyingWithBlockAck.empty ())
306  {
307  // a station will reply immediately with a Block Ack
308  timerType = WifiTxTimer::WAIT_BLOCK_ACK;
309  responseTxVector = &acknowledgment->stationsReplyingWithBlockAck.begin ()->second.blockAckTxVector;
310  psdu = GetPsduTo (acknowledgment->stationsReplyingWithBlockAck.begin ()->first, m_psduMap);
311  }
312  // else no station will reply immediately
313  }
314  /*
315  * Acknowledgment via a MU-BAR Trigger Frame sent as single user frame
316  */
318  {
319  WifiDlMuTfMuBar* acknowledgment = static_cast<WifiDlMuTfMuBar*> (m_txParams.m_acknowledgment.get ());
320 
321  if (m_triggerFrame == nullptr)
322  {
323  // we are transmitting the DL MU PPDU and have to schedule the
324  // transmission of a MU-BAR Trigger Frame.
325  // Create a TXVECTOR by "merging" all the BlockAck TXVECTORs
326  std::map<uint16_t, CtrlBAckRequestHeader> recipients;
327 
328  NS_ASSERT (!acknowledgment->stationsReplyingWithBlockAck.empty ());
329  auto staIt = acknowledgment->stationsReplyingWithBlockAck.begin ();
330  WifiTxVector txVector = staIt->second.blockAckTxVector;
331  while (staIt != acknowledgment->stationsReplyingWithBlockAck.end ())
332  {
333  NS_ASSERT (m_apMac != 0);
334  uint16_t staId = m_apMac->GetAssociationId (staIt->first);
335 
336  txVector.SetHeMuUserInfo (staId, staIt->second.blockAckTxVector.GetHeMuUserInfo (staId));
337  recipients.emplace (staId, staIt->second.barHeader);
338 
339  staIt++;
340  }
341  // set the Length field of the response TXVECTOR, which is needed to correctly
342  // set the UL Length field of the MU-BAR Trigger Frame
343  txVector.SetLength (acknowledgment->ulLength);
344 
345  NS_ASSERT (m_edca != 0);
346  m_edca->ScheduleBar (PrepareMuBar (txVector, recipients));
347  }
348  else
349  {
350  // we are transmitting the MU-BAR following the DL MU PPDU after a SIFS.
351  // m_psduMap and m_txParams are still the same as when the DL MU PPDU was sent.
352  // record the set of stations expected to send a BlockAck frame
353  m_staExpectTbPpduFrom.clear ();
354  for (auto& station : acknowledgment->stationsReplyingWithBlockAck)
355  {
356  m_staExpectTbPpduFrom.insert (station.first);
357  }
358 
359  Ptr<WifiPsdu> triggerPsdu = GetWifiPsdu (m_triggerFrame, acknowledgment->muBarTxVector);
360  Time txDuration = m_phy->CalculateTxDuration (triggerPsdu->GetSize (),
361  acknowledgment->muBarTxVector,
362  m_phy->GetPhyBand ());
363  // update acknowledgmentTime to correctly set the Duration/ID
364  acknowledgment->acknowledgmentTime -= (m_phy->GetSifs () + txDuration);
366 
367  responseTxVector = &acknowledgment->stationsReplyingWithBlockAck.begin ()->second.blockAckTxVector;
368  Time timeout = txDuration + m_phy->GetSifs () + m_phy->GetSlot ()
369  + m_phy->CalculatePhyPreambleAndHeaderDuration (*responseTxVector);
370 
374  m_channelAccessManager->NotifyAckTimeoutStartNow (timeout);
375 
376  ForwardPsduDown (triggerPsdu, acknowledgment->muBarTxVector);
377  return;
378  }
379  }
380  /*
381  * Acknowledgment requested by MU-BAR TFs aggregated to PSDUs in the DL MU PPDU
382  */
384  {
385  WifiDlMuAggregateTf* acknowledgment = static_cast<WifiDlMuAggregateTf*> (m_txParams.m_acknowledgment.get ());
386 
387  // record the set of stations expected to send a BlockAck frame
388  m_staExpectTbPpduFrom.clear ();
389 
390  for (auto& station : acknowledgment->stationsReplyingWithBlockAck)
391  {
392  m_staExpectTbPpduFrom.insert (station.first);
393  // check that the station that is expected to send a BlockAck frame is
394  // actually the receiver of a PSDU
395  auto psduMapIt = std::find_if (m_psduMap.begin (), m_psduMap.end (),
396  [&station] (std::pair<uint16_t, Ptr<WifiPsdu>> psdu)
397  { return psdu.second->GetAddr1 () == station.first; });
398 
399  NS_ASSERT (psduMapIt != m_psduMap.end ());
400  // add a MU-BAR Trigger Frame to the PSDU
401  std::vector<Ptr<WifiMacQueueItem>> mpduList (psduMapIt->second->begin (), psduMapIt->second->end ());
402  NS_ASSERT (mpduList.size () == psduMapIt->second->GetNMpdus ());
403  // set the Length field of the response TXVECTOR, which is needed to correctly
404  // set the UL Length field of the MU-BAR Trigger Frame
405  station.second.blockAckTxVector.SetLength (acknowledgment->ulLength);
406  mpduList.push_back (PrepareMuBar (station.second.blockAckTxVector,
407  {{psduMapIt->first, station.second.barHeader}}));
408  psduMapIt->second = Create<WifiPsdu> (std::move (mpduList));
409  }
410 
412  responseTxVector = &acknowledgment->stationsReplyingWithBlockAck.begin ()->second.blockAckTxVector;
413  }
414  /*
415  * Basic Trigger Frame starting an UL MU transmission
416  */
417  else if (m_txParams.m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA)
418  {
419  // the PSDU map being sent must contain a (Basic) Trigger Frame
420  NS_ASSERT (m_psduMap.size () == 1 && m_psduMap.begin ()->first == SU_STA_ID
421  && (mpdu = *m_psduMap.begin ()->second->begin ())->GetHeader ().IsTrigger ());
422 
423  WifiUlMuMultiStaBa* acknowledgment = static_cast<WifiUlMuMultiStaBa*> (m_txParams.m_acknowledgment.get ());
424 
425  // record the set of stations solicited by this Trigger Frame
426  m_staExpectTbPpduFrom.clear ();
427 
428  for (const auto& station : acknowledgment->stationsReceivingMultiStaBa)
429  {
430  m_staExpectTbPpduFrom.insert (station.first.first);
431  }
432 
433  // Reset stationsReceivingMultiStaBa, which will be filled as soon as
434  // TB PPDUs are received
435  acknowledgment->stationsReceivingMultiStaBa.clear ();
436  acknowledgment->baType.m_bitmapLen.clear ();
437 
438  // Add a SIFS and the TB PPDU duration to the acknowledgment time of the
439  // Trigger Frame, so that its Duration/ID is correctly computed
440  NS_ASSERT (m_muScheduler != 0);
441  acknowledgment->acknowledgmentTime += m_mac->GetWifiPhy ()->GetSifs ()
442  + m_muScheduler->GetUlMuInfo ().tbPpduDuration;
443 
445  responseTxVector = &acknowledgment->tbPpduTxVector;
446  }
447  /*
448  * BSRP Trigger Frame
449  */
450  else if (m_txParams.m_acknowledgment->method == WifiAcknowledgment::NONE
451  && !m_txParams.m_txVector.IsUlMu ()
452  && m_psduMap.size () == 1 && m_psduMap.begin ()->first == SU_STA_ID
453  && (mpdu = *m_psduMap.begin ()->second->begin ())->GetHeader ().IsTrigger ())
454  {
455  CtrlTriggerHeader trigger;
456  mpdu->GetPacket ()->PeekHeader (trigger);
457  NS_ASSERT (trigger.IsBsrp ());
458  NS_ASSERT (m_apMac != 0);
459 
460  // record the set of stations solicited by this Trigger Frame
461  m_staExpectTbPpduFrom.clear ();
462 
463  for (const auto& userInfo : trigger)
464  {
465  auto staIt = m_apMac->GetStaList ().find (userInfo.GetAid12 ());
466  NS_ASSERT (staIt != m_apMac->GetStaList ().end ());
467  m_staExpectTbPpduFrom.insert (staIt->second);
468  }
469 
470  // Add a SIFS and the TB PPDU duration to the acknowledgment time of the
471  // Trigger Frame, so that its Duration/ID is correctly computed
472  WifiNoAck* acknowledgment = static_cast<WifiNoAck*> (m_txParams.m_acknowledgment.get ());
473  txVector = trigger.GetHeTbTxVector (trigger.begin ()->GetAid12 ());
474  acknowledgment->acknowledgmentTime += m_mac->GetWifiPhy ()->GetSifs ()
475  + HePhy::ConvertLSigLengthToHeTbPpduDuration (trigger.GetUlLength (),
476  txVector,
477  m_phy->GetPhyBand ());
478 
480  responseTxVector = &txVector;
481  }
482  /*
483  * TB PPDU solicited by a Basic Trigger Frame
484  */
485  else if (m_txParams.m_txVector.IsUlMu ()
486  && m_txParams.m_acknowledgment->method == WifiAcknowledgment::ACK_AFTER_TB_PPDU)
487  {
488  NS_ASSERT (m_psduMap.size () == 1);
490  NS_ASSERT (m_staMac != 0 && m_staMac->IsAssociated ());
491  txVector = m_mac->GetWifiRemoteStationManager ()->GetBlockAckTxVector (m_psduMap.begin ()->second->GetAddr1 (),
492  m_txParams.m_txVector);
493  responseTxVector = &txVector;
494  }
495  /*
496  * QoS Null frames solicited by a BSRP Trigger Frame
497  */
498  else if (m_txParams.m_txVector.IsUlMu ()
499  && m_txParams.m_acknowledgment->method == WifiAcknowledgment::NONE)
500  {
501  // No response is expected, so do nothing.
502  }
503  else
504  {
505  NS_ABORT_MSG ("Unable to handle the selected acknowledgment method ("
506  << m_txParams.m_acknowledgment.get () << ")");
507  }
508 
509  // create a map of Ptr<const WifiPsdu>, as required by the PHY
510  WifiConstPsduMap psduMap;
511  for (const auto& psdu : m_psduMap)
512  {
513  psduMap.emplace (psdu.first, psdu.second);
514  }
515 
516  Time txDuration;
517  if (m_txParams.m_txVector.IsUlMu ())
518  {
519  txDuration = HePhy::ConvertLSigLengthToHeTbPpduDuration (m_txParams.m_txVector.GetLength (),
520  m_txParams.m_txVector,
521  m_phy->GetPhyBand ());
522  }
523  else
524  {
525  txDuration = m_phy->CalculateTxDuration (psduMap, m_txParams.m_txVector, m_phy->GetPhyBand ());
526 
527  // Set Duration/ID
528  Time durationId = GetPsduDurationId (txDuration, m_txParams);
529  for (auto& psdu : m_psduMap)
530  {
531  psdu.second->SetDuration (durationId);
532  }
533  }
534 
535  if (timerType == WifiTxTimer::NOT_RUNNING)
536  {
537  if (!m_txParams.m_txVector.IsUlMu ())
538  {
540  }
541  }
542  else
543  {
544  Time timeout = txDuration + m_phy->GetSifs () + m_phy->GetSlot ()
545  + m_phy->CalculatePhyPreambleAndHeaderDuration (*responseTxVector);
546  m_channelAccessManager->NotifyAckTimeoutStartNow (timeout);
547 
548  // start timer
549  switch (timerType)
550  {
552  NS_ASSERT (mpdu != nullptr);
553  m_txTimer.Set (timerType, timeout, &HeFrameExchangeManager::NormalAckTimeout,
554  this, mpdu, m_txParams.m_txVector);
555  break;
557  NS_ASSERT (psdu != nullptr);
558  m_txTimer.Set (timerType, timeout, &HeFrameExchangeManager::BlockAckTimeout,
559  this, psdu, m_txParams.m_txVector);
560  break;
562  m_txTimer.Set (timerType, timeout, &HeFrameExchangeManager::BlockAcksInTbPpduTimeout, this,
563  &m_psduMap, &m_staExpectTbPpduFrom, m_staExpectTbPpduFrom.size ());
564  break;
567  m_txTimer.Set (timerType, timeout, &HeFrameExchangeManager::TbPpduTimeout, this,
568  &m_psduMap, &m_staExpectTbPpduFrom, m_staExpectTbPpduFrom.size ());
569  break;
572  this, m_psduMap.begin ()->second, m_txParams.m_txVector);
573  break;
574  default:
575  NS_ABORT_MSG ("Unknown timer type: " << timerType);
576  break;
577  }
578  }
579 
580  // transmit the map of PSDUs
581  ForwardPsduMapDown (psduMap, m_txParams.m_txVector);
582 }
583 
584 void
585 HeFrameExchangeManager::ForwardPsduMapDown (WifiConstPsduMap psduMap, WifiTxVector& txVector)
586 {
587  NS_LOG_FUNCTION (this << psduMap << txVector);
588 
589  for (const auto& psdu : psduMap)
590  {
591  NS_LOG_DEBUG ("Transmitting: [STAID=" << psdu.first << ", " << *psdu.second << "]");
592  }
593  NS_LOG_DEBUG ("TXVECTOR: " << txVector);
594  for (const auto& psdu : psduMap)
595  {
596  NotifyTxToEdca (psdu.second);
597  }
598  if (psduMap.size () > 1 || psduMap.begin ()->second->IsAggregate () || psduMap.begin ()->second->IsSingle ())
599  {
600  txVector.SetAggregation (true);
601  }
602 
603  m_phy->Send (psduMap, txVector);
604 }
605 
607 HeFrameExchangeManager::PrepareMuBar (const WifiTxVector& responseTxVector,
608  std::map<uint16_t, CtrlBAckRequestHeader> recipients) const
609 {
610  NS_LOG_FUNCTION (this << responseTxVector);
611  NS_ASSERT (responseTxVector.GetHeMuUserInfoMap ().size () == recipients.size ());
612  NS_ASSERT (!recipients.empty ());
613 
614  CtrlTriggerHeader muBar (TriggerFrameType::MU_BAR_TRIGGER, responseTxVector);
615  SetTargetRssi (muBar);
616  Mac48Address rxAddress;
617 
618  // Add the Trigger Dependent User Info subfield to every User Info field
619  for (auto& userInfo : muBar)
620  {
621  auto recipientIt = recipients.find (userInfo.GetAid12 ());
622  NS_ASSERT (recipientIt != recipients.end ());
623 
624  // Store the BAR in the Trigger Dependent User Info subfield
625  userInfo.SetMuBarTriggerDepUserInfo (recipientIt->second);
626  }
627 
628  Ptr<Packet> bar = Create<Packet> ();
629  bar->AddHeader (muBar);
630  // "If the Trigger frame has one User Info field and the AID12 subfield of the
631  // User Info contains the AID of a STA, then the RA field is set to the address
632  // of that STA". Otherwise, it is set to the broadcast address (Sec. 9.3.1.23 -
633  // 802.11ax amendment draft 3.0)
634  if (muBar.GetNUserInfoFields () > 1)
635  {
636  rxAddress = Mac48Address::GetBroadcast ();
637  }
638  else
639  {
640  NS_ASSERT (m_apMac != 0);
641  rxAddress = m_apMac->GetStaList ().at (recipients.begin ()->first);
642  }
643 
644  WifiMacHeader hdr;
646  hdr.SetAddr1 (rxAddress);
647  hdr.SetAddr2 (m_self);
648  hdr.SetDsNotTo ();
649  hdr.SetDsNotFrom ();
650  hdr.SetNoRetry ();
651  hdr.SetNoMoreFragments ();
652 
653  return Create<WifiMacQueueItem> (bar, hdr);
654 }
655 
656 void
657 HeFrameExchangeManager::CalculateAcknowledgmentTime (WifiAcknowledgment* acknowledgment) const
658 {
659  NS_LOG_FUNCTION (this << acknowledgment);
660  NS_ASSERT (acknowledgment != nullptr);
661 
662  /*
663  * Acknowledgment via a sequence of BlockAckReq and BlockAck frames
664  */
665  if (acknowledgment->method == WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE)
666  {
667  WifiDlMuBarBaSequence* dlMuBarBaAcknowledgment = static_cast<WifiDlMuBarBaSequence*> (acknowledgment);
668 
669  Time duration = Seconds (0);
670 
671  // normal ack or implicit BAR policy can be used for (no more than) one receiver
672  NS_ABORT_IF (dlMuBarBaAcknowledgment->stationsReplyingWithNormalAck.size ()
673  + dlMuBarBaAcknowledgment->stationsReplyingWithBlockAck.size () > 1);
674 
675  if (!dlMuBarBaAcknowledgment->stationsReplyingWithNormalAck.empty ())
676  {
677  const auto& info = dlMuBarBaAcknowledgment->stationsReplyingWithNormalAck.begin ()->second;
678  duration += m_phy->GetSifs ()
679  + m_phy->CalculateTxDuration (GetAckSize (), info.ackTxVector, m_phy->GetPhyBand ());
680  }
681 
682  if (!dlMuBarBaAcknowledgment->stationsReplyingWithBlockAck.empty ())
683  {
684  const auto& info = dlMuBarBaAcknowledgment->stationsReplyingWithBlockAck.begin ()->second;
685  duration += m_phy->GetSifs ()
686  + m_phy->CalculateTxDuration (GetBlockAckSize (info.baType),
687  info.blockAckTxVector, m_phy->GetPhyBand ());
688  }
689 
690  for (const auto& stations : dlMuBarBaAcknowledgment->stationsSendBlockAckReqTo)
691  {
692  const auto& info = stations.second;
693  duration += m_phy->GetSifs ()
694  + m_phy->CalculateTxDuration (GetBlockAckRequestSize (info.barType),
695  info.blockAckReqTxVector, m_phy->GetPhyBand ())
696  + m_phy->GetSifs ()
697  + m_phy->CalculateTxDuration (GetBlockAckSize (info.baType),
698  info.blockAckTxVector, m_phy->GetPhyBand ());
699  }
700 
701  dlMuBarBaAcknowledgment->acknowledgmentTime = duration;
702  }
703  /*
704  * Acknowledgment via a MU-BAR Trigger Frame sent as single user frame
705  */
706  else if (acknowledgment->method == WifiAcknowledgment::DL_MU_TF_MU_BAR)
707  {
708  WifiDlMuTfMuBar* dlMuTfMuBarAcknowledgment = static_cast<WifiDlMuTfMuBar*> (acknowledgment);
709 
710  Time duration = Seconds (0);
711 
712  for (const auto& stations : dlMuTfMuBarAcknowledgment->stationsReplyingWithBlockAck)
713  {
714  // compute the TX duration of the BlockAck response from this receiver.
715  const auto& info = stations.second;
716  NS_ASSERT (info.blockAckTxVector.GetHeMuUserInfoMap ().size () == 1);
717  uint16_t staId = info.blockAckTxVector.GetHeMuUserInfoMap ().begin ()->first;
718  Time currBlockAckDuration = m_phy->CalculateTxDuration (GetBlockAckSize (info.baType),
719  info.blockAckTxVector,
720  m_phy->GetPhyBand (),
721  staId);
722  // update the max duration among all the Block Ack responses
723  if (currBlockAckDuration > duration)
724  {
725  duration = currBlockAckDuration;
726  }
727  }
728 
729  // The computed duration may not be coded exactly in the L-SIG length, hence determine
730  // the exact duration corresponding to the value that will be coded in this field.
731  dlMuTfMuBarAcknowledgment->ulLength = HePhy::ConvertHeTbPpduDurationToLSigLength (duration, m_phy->GetPhyBand ());
732  WifiTxVector& txVector = dlMuTfMuBarAcknowledgment->stationsReplyingWithBlockAck.begin ()->second.blockAckTxVector;
733  duration = HePhy::ConvertLSigLengthToHeTbPpduDuration (dlMuTfMuBarAcknowledgment->ulLength,
734  txVector, m_phy->GetPhyBand ());
735 
736  uint32_t muBarSize = GetMuBarSize (dlMuTfMuBarAcknowledgment->barTypes);
737  if (dlMuTfMuBarAcknowledgment->muBarTxVector.GetModulationClass () >= WIFI_MOD_CLASS_VHT)
738  {
739  // MU-BAR TF will be sent as an S-MPDU
740  muBarSize = MpduAggregator::GetSizeIfAggregated (muBarSize, 0);
741  }
742  dlMuTfMuBarAcknowledgment->acknowledgmentTime = m_phy->GetSifs ()
743  + m_phy->CalculateTxDuration (muBarSize,
744  dlMuTfMuBarAcknowledgment->muBarTxVector,
745  m_phy->GetPhyBand ())
746  + m_phy->GetSifs () + duration;
747  }
748  /*
749  * Acknowledgment requested by MU-BAR TFs aggregated to PSDUs in the DL MU PPDU
750  */
751  else if (acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF)
752  {
753  WifiDlMuAggregateTf* dlMuAggrTfAcknowledgment = static_cast<WifiDlMuAggregateTf*> (acknowledgment);
754 
755  Time duration = Seconds (0);
756 
757  for (const auto& stations : dlMuAggrTfAcknowledgment->stationsReplyingWithBlockAck)
758  {
759  // compute the TX duration of the BlockAck response from this receiver.
760  const auto& info = stations.second;
761  NS_ASSERT (info.blockAckTxVector.GetHeMuUserInfoMap ().size () == 1);
762  uint16_t staId = info.blockAckTxVector.GetHeMuUserInfoMap ().begin ()->first;
763  Time currBlockAckDuration = m_phy->CalculateTxDuration (GetBlockAckSize (info.baType),
764  info.blockAckTxVector,
765  m_phy->GetPhyBand (),
766  staId);
767  // update the max duration among all the Block Ack responses
768  if (currBlockAckDuration > duration)
769  {
770  duration = currBlockAckDuration;
771  }
772  }
773 
774  // The computed duration may not be coded exactly in the L-SIG length, hence determine
775  // the exact duration corresponding to the value that will be coded in this field.
776  dlMuAggrTfAcknowledgment->ulLength = HePhy::ConvertHeTbPpduDurationToLSigLength (duration, m_phy->GetPhyBand ());
777  WifiTxVector& txVector = dlMuAggrTfAcknowledgment->stationsReplyingWithBlockAck.begin ()->second.blockAckTxVector;
778  duration = HePhy::ConvertLSigLengthToHeTbPpduDuration (dlMuAggrTfAcknowledgment->ulLength,
779  txVector, m_phy->GetPhyBand ());
780 
781  dlMuAggrTfAcknowledgment->acknowledgmentTime = m_phy->GetSifs () + duration;
782  }
783  /*
784  * Basic Trigger Frame starting an UL MU transmission
785  */
786  else if (acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA)
787  {
788  WifiUlMuMultiStaBa* ulMuMultiStaBa = static_cast<WifiUlMuMultiStaBa*> (acknowledgment);
789 
790  Time duration = m_phy->CalculateTxDuration (GetBlockAckSize (ulMuMultiStaBa->baType),
791  ulMuMultiStaBa->multiStaBaTxVector,
792  m_phy->GetPhyBand ());
793  ulMuMultiStaBa->acknowledgmentTime = m_phy->GetSifs () + duration;
794  }
795  /*
796  * TB PPDU solicired by a Basic or BSRP Trigger Frame
797  */
798  else if (acknowledgment->method == WifiAcknowledgment::ACK_AFTER_TB_PPDU)
799  {
800  // The station solicited by the Trigger Frame does not have to account
801  // for the actual acknowledgment time since it is given the PPDU duration
802  // through the Trigger Frame
803  acknowledgment->acknowledgmentTime = Seconds (0);
804  }
805  else
806  {
807  VhtFrameExchangeManager::CalculateAcknowledgmentTime (acknowledgment);
808  }
809 }
810 
811 Time
812 HeFrameExchangeManager::GetTxDuration (uint32_t ppduPayloadSize, Mac48Address receiver,
813  const WifiTxParameters& txParams) const
814 {
815  if (!txParams.m_txVector.IsMu ())
816  {
817  return VhtFrameExchangeManager::GetTxDuration (ppduPayloadSize, receiver, txParams);
818  }
819 
820  NS_ASSERT_MSG (!txParams.m_txVector.IsDlMu () || m_apMac != 0, "DL MU can be done by an AP");
821  NS_ASSERT_MSG (!txParams.m_txVector.IsUlMu () || m_staMac != 0, "UL MU can be done by a STA");
822 
823  if (txParams.m_acknowledgment
824  && txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF)
825  {
826  // we need to account for the size of the aggregated MU-BAR Trigger Frame
827  WifiDlMuAggregateTf* acknowledgment = static_cast<WifiDlMuAggregateTf*> (txParams.m_acknowledgment.get ());
828 
829  const auto& info = acknowledgment->stationsReplyingWithBlockAck.find (receiver);
830  NS_ASSERT (info != acknowledgment->stationsReplyingWithBlockAck.end ());
831 
832  ppduPayloadSize = MpduAggregator::GetSizeIfAggregated (info->second.muBarSize, ppduPayloadSize);
833  }
834 
835  uint16_t staId = (txParams.m_txVector.IsDlMu () ? m_apMac->GetAssociationId (receiver)
836  : m_staMac->GetAssociationId ());
837  Time psduDuration = m_phy->CalculateTxDuration (ppduPayloadSize, txParams.m_txVector,
838  m_phy->GetPhyBand (), staId);
839 
840  return std::max (psduDuration, txParams.m_txDuration);
841 }
842 
843 void
844 HeFrameExchangeManager::TbPpduTimeout (WifiPsduMap* psduMap,
845  const std::set<Mac48Address>* staMissedTbPpduFrom,
846  std::size_t nSolicitedStations)
847 {
848  NS_LOG_FUNCTION (this << psduMap << staMissedTbPpduFrom->size () << nSolicitedStations);
849 
850  NS_ASSERT (psduMap != nullptr);
851  NS_ASSERT (psduMap->size () == 1 && psduMap->begin ()->first == SU_STA_ID
852  && psduMap->begin ()->second->GetHeader (0).IsTrigger ());
853 
854  // This method is called if some station(s) did not send a TB PPDU
855  NS_ASSERT (!staMissedTbPpduFrom->empty ());
856  NS_ASSERT (m_edca != 0);
857 
858  if (staMissedTbPpduFrom->size () == nSolicitedStations)
859  {
860  // no station replied, the transmission failed
861  m_edca->UpdateFailedCw ();
862 
863  TransmissionFailed ();
864  }
865  else if (!m_multiStaBaEvent.IsRunning ())
866  {
867  m_edca->ResetCw ();
868  TransmissionSucceeded ();
869  }
870 
871  m_psduMap.clear ();
872 }
873 
874 void
875 HeFrameExchangeManager::BlockAcksInTbPpduTimeout (WifiPsduMap* psduMap,
876  const std::set<Mac48Address>* staMissedBlockAckFrom,
877  std::size_t nSolicitedStations)
878 {
879  NS_LOG_FUNCTION (this << psduMap << nSolicitedStations);
880 
881  NS_ASSERT (psduMap != nullptr);
882  NS_ASSERT (m_txParams.m_acknowledgment
883  && (m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF
884  || m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_TF_MU_BAR));
885 
886  // This method is called if some station(s) did not send a BlockAck frame in a TB PPDU
887  NS_ASSERT (!staMissedBlockAckFrom->empty ());
888 
889  bool resetCw;
890 
891  if (staMissedBlockAckFrom->size () == nSolicitedStations)
892  {
893  // no station replied, the transmission failed
894  // call ReportDataFailed to increase SRC/LRC
895  m_mac->GetWifiRemoteStationManager ()->ReportDataFailed (*psduMap->begin ()->second->begin ());
896  resetCw = false;
897  }
898  else
899  {
900  // the transmission succeeded
901  resetCw = true;
902  }
903 
904  m_triggerFrame = nullptr; // this is strictly needed for DL_MU_TF_MU_BAR only
905 
906  for (const auto& sta : *staMissedBlockAckFrom)
907  {
908  Ptr<WifiPsdu> psdu = GetPsduTo (sta, *psduMap);
909  NS_ASSERT (psdu != nullptr);
910  // If the QSRC[AC] or the QLRC[AC] has reached dot11ShortRetryLimit or dot11LongRetryLimit
911  // respectively, CW[AC] shall be reset to CWmin[AC] (sec. 10.22.2.2 of 802.11-2016).
912  // We should get that psduResetCw is the same for all PSDUs, but the handling of QSRC/QLRC
913  // needs to be aligned to the specifications.
914  bool psduResetCw;
915  MissedBlockAck (psdu, m_txParams.m_txVector, psduResetCw);
916  resetCw = resetCw || psduResetCw;
917  }
918 
919  NS_ASSERT (m_edca != 0);
920 
921  if (resetCw)
922  {
923  m_edca->ResetCw ();
924  }
925  else
926  {
927  m_edca->UpdateFailedCw ();
928  }
929 
930  if (staMissedBlockAckFrom->size () == nSolicitedStations)
931  {
932  // no station replied, the transmission failed
933  TransmissionFailed ();
934  }
935  else
936  {
937  TransmissionSucceeded ();
938  }
939  m_psduMap.clear ();
940 }
941 
942 void
943 HeFrameExchangeManager::BlockAckAfterTbPpduTimeout (Ptr<WifiPsdu> psdu, const WifiTxVector& txVector)
944 {
945  NS_LOG_FUNCTION (this << *psdu << txVector);
946 
947  bool resetCw;
948 
949  // call ReportDataFailed to increase SRC/LRC
950  m_mac->GetWifiRemoteStationManager ()->ReportDataFailed (*psdu->begin ());
951 
952  MissedBlockAck (psdu, m_txParams.m_txVector, resetCw);
953 
954  // This is a PSDU sent in a TB PPDU. An HE STA resumes the EDCA backoff procedure
955  // without modifying CW or the backoff counter for the associated EDCAF, after
956  // transmission of an MPDU in a TB PPDU regardless of whether the STA has received
957  // the corresponding acknowledgment frame in response to the MPDU sent in the TB PPDU
958  // (Sec. 10.22.2.2 of 11ax Draft 3.0)
959  m_psduMap.clear ();
960 }
961 
963 HeFrameExchangeManager::GetHeTbTxVector (CtrlTriggerHeader trigger, Mac48Address triggerSender) const
964 {
965  NS_ASSERT (triggerSender != m_self); //TxPower information is used only by STAs, it is useless for the sending AP (which can directly use CtrlTriggerHeader::GetHeTbTxVector)
966  NS_ASSERT (m_staMac != nullptr);
967  uint16_t staId = m_staMac->GetAssociationId ();
968  auto userInfoIt = trigger.FindUserInfoWithAid (staId);
969  NS_ASSERT (userInfoIt != trigger.end ());
970 
971  WifiTxVector v = trigger.GetHeTbTxVector (staId);
972 
973  Ptr<HeConfiguration> heConfiguration = m_mac->GetHeConfiguration ();
974  NS_ASSERT_MSG (heConfiguration != 0, "This STA has to be an HE station to send an HE TB PPDU");
975  v.SetBssColor (heConfiguration->GetBssColor ());
976 
977  uint8_t powerLevel = m_mac->GetWifiRemoteStationManager ()->GetDefaultTxPowerLevel ();
995  int8_t pathLossDb = trigger.GetApTxPower () - static_cast<int8_t> (m_mac->GetWifiRemoteStationManager ()->GetMostRecentRssi (triggerSender)); //cast RSSI to be on equal footing with AP Tx power information
996  double reqTxPowerDbm = static_cast<double> (userInfoIt->GetUlTargetRssi () + pathLossDb);
997 
998  //Convert the transmit power to a power level
999  uint8_t numPowerLevels = m_phy->GetNTxPower ();
1000  if (numPowerLevels > 1)
1001  {
1002  double stepDbm = (m_phy->GetTxPowerEnd () - m_phy->GetTxPowerStart ()) / (numPowerLevels - 1);
1003  powerLevel = static_cast<uint8_t> (ceil ((reqTxPowerDbm - m_phy->GetTxPowerStart ()) / stepDbm)); //better be slightly above so as to satisfy target UL RSSI
1004  if (powerLevel > numPowerLevels)
1005  {
1006  powerLevel = numPowerLevels; //capping will trigger warning below
1007  }
1008  }
1009  if (reqTxPowerDbm > m_phy->GetPowerDbm (powerLevel))
1010  {
1011  NS_LOG_WARN ("The requested power level (" << reqTxPowerDbm << "dBm) cannot be satisfied (max: " << m_phy->GetTxPowerEnd () << "dBm)");
1012  }
1013  v.SetTxPowerLevel (powerLevel);
1014  NS_LOG_LOGIC ("UL power control: "
1015  << "input {pathLoss=" << pathLossDb << "dB, reqTxPower=" << reqTxPowerDbm << "dBm}"
1016  << " output {powerLevel=" << +powerLevel << " -> " << m_phy->GetPowerDbm (powerLevel) << "dBm}"
1017  << " PHY power capa {min=" << m_phy->GetTxPowerStart () << "dBm, max=" << m_phy->GetTxPowerEnd () << "dBm, levels:" << +numPowerLevels << "}");
1018 
1019  return v;
1020 }
1021 
1022 void
1023 HeFrameExchangeManager::SetTargetRssi (CtrlTriggerHeader& trigger) const
1024 {
1025  NS_LOG_FUNCTION (this);
1026  NS_ASSERT (m_apMac != 0);
1027 
1028  trigger.SetApTxPower (static_cast<int8_t> (m_phy->GetPowerDbm (m_mac->GetWifiRemoteStationManager ()->GetDefaultTxPowerLevel ())));
1029  for (auto& userInfo : trigger)
1030  {
1031  const auto staList = m_apMac->GetStaList ();
1032  auto itAidAddr = staList.find (userInfo.GetAid12 ());
1033  NS_ASSERT (itAidAddr != staList.end ());
1034  int8_t rssi = static_cast<int8_t> (m_mac->GetWifiRemoteStationManager ()->GetMostRecentRssi (itAidAddr->second));
1035  rssi = (rssi >= -20) ? -20 : ((rssi <= -110) ? -110 : rssi); //cap so as to keep within [-110; -20] dBm
1036  userInfo.SetUlTargetRssi (rssi);
1037  }
1038 }
1039 
1040 void
1041 HeFrameExchangeManager::SendMultiStaBlockAck (const WifiTxParameters& txParams)
1042 {
1043  NS_LOG_FUNCTION (this << &txParams);
1044 
1045  NS_ASSERT (m_apMac != 0);
1046  NS_ASSERT (txParams.m_acknowledgment
1047  && txParams.m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
1048  WifiUlMuMultiStaBa* acknowledgment = static_cast<WifiUlMuMultiStaBa*> (txParams.m_acknowledgment.get ());
1049 
1050  NS_ASSERT (!acknowledgment->stationsReceivingMultiStaBa.empty ());
1051 
1052  CtrlBAckResponseHeader blockAck;
1053  blockAck.SetType (acknowledgment->baType);
1054 
1055  Mac48Address receiver;
1056 
1057  for (const auto& staInfo : acknowledgment->stationsReceivingMultiStaBa)
1058  {
1059  receiver = staInfo.first.first;
1060  uint8_t tid = staInfo.first.second;
1061  std::size_t index = staInfo.second;
1062 
1063  blockAck.SetAid11 (m_apMac->GetAssociationId (receiver), index);
1064  blockAck.SetTidInfo (tid, index);
1065 
1066  if (tid == 14)
1067  {
1068  // All-ack context
1069  NS_LOG_DEBUG ("Multi-STA Block Ack: Sending All-ack to=" << receiver);
1070  blockAck.SetAckType (true, index);
1071  continue;
1072  }
1073 
1074  if (acknowledgment->baType.m_bitmapLen.at (index) == 0)
1075  {
1076  // Acknowledgment context
1077  NS_LOG_DEBUG ("Multi-STA Block Ack: Sending Ack to=" << receiver);
1078  blockAck.SetAckType (true, index);
1079  }
1080  else
1081  {
1082  // Block acknowledgment context
1083  blockAck.SetAckType (false, index);
1084 
1085  auto addressTidPair = staInfo.first;
1086  auto agreementIt = m_agreements.find (addressTidPair);
1087  NS_ASSERT (agreementIt != m_agreements.end ());
1088  agreementIt->second.FillBlockAckBitmap (&blockAck, index);
1089  NS_LOG_DEBUG ("Multi-STA Block Ack: Sending Block Ack with seq=" << blockAck.GetStartingSequence (index)
1090  << " to=" << receiver << " tid=" << +tid);
1091  }
1092  }
1093 
1094  WifiMacHeader hdr;
1096  hdr.SetAddr1 (acknowledgment->stationsReceivingMultiStaBa.size () == 1 ? receiver : Mac48Address::GetBroadcast ());
1097  hdr.SetAddr2 (m_self);
1098  hdr.SetDsNotFrom ();
1099  hdr.SetDsNotTo ();
1100 
1101  Ptr<Packet> packet = Create<Packet> ();
1102  packet->AddHeader (blockAck);
1103  Ptr<WifiPsdu> psdu = GetWifiPsdu (Create<WifiMacQueueItem> (packet, hdr),
1104  acknowledgment->multiStaBaTxVector);
1105 
1106  // The Duration/ID field in a BlockAck frame transmitted in response to a frame
1107  // carried in HE TB PPDU is set according to the multiple protection settings
1108  // (Sec. 9.2.5.7 of 802.11ax D3.0)
1109  Time txDuration = m_phy->CalculateTxDuration (GetBlockAckSize (acknowledgment->baType),
1110  acknowledgment->multiStaBaTxVector,
1111  m_phy->GetPhyBand ());
1112  WifiTxParameters params;
1113  // if the TXOP limit is null, GetPsduDurationId returns the acknowledgment time,
1114  // hence we set an method with acknowledgment time equal to zero.
1115  params.m_acknowledgment = std::unique_ptr<WifiAcknowledgment> (new WifiNoAck);
1116  psdu->SetDuration (GetPsduDurationId (txDuration, params));
1117 
1118  psdu->GetPayload (0)->AddPacketTag (m_muSnrTag);
1119 
1120  ForwardPsduDown (psdu, acknowledgment->multiStaBaTxVector);
1121 
1122  // continue with the TXOP if time remains
1123  m_psduMap.clear ();
1124  m_edca->ResetCw ();
1125  m_muSnrTag.Reset ();
1126  Simulator::Schedule (txDuration, &HeFrameExchangeManager::TransmissionSucceeded, this);
1127 }
1128 
1129 void
1130 HeFrameExchangeManager::ReceiveBasicTrigger (const CtrlTriggerHeader& trigger, const WifiMacHeader& hdr)
1131 {
1132  NS_LOG_FUNCTION (this << trigger << hdr);
1133  NS_ASSERT (trigger.IsBasic ());
1134  NS_ASSERT (m_staMac != 0 && m_staMac->IsAssociated ());
1135 
1136  NS_LOG_DEBUG ("Received a Trigger Frame (basic variant) soliciting a transmission");
1137 
1138  if (trigger.GetCsRequired () && hdr.GetAddr2 () != m_txopHolder && m_navEnd > Simulator::Now ())
1139  {
1140  NS_LOG_DEBUG ("Carrier Sensing required and channel busy, do nothing");
1141  return;
1142  }
1143 
1144  // Starting from the Preferred AC indicated in the Trigger Frame, check if there
1145  // is either a pending BlockAckReq frame or a data frame that can be transmitted
1146  // in the allocated time and is addressed to a station with which a Block Ack
1147  // agreement has been established.
1148 
1149  // create the sequence of TIDs to check
1150  std::vector<uint8_t> tids;
1151  uint16_t staId = m_staMac->GetAssociationId ();
1152  AcIndex preferredAc = trigger.FindUserInfoWithAid (staId)->GetPreferredAc ();
1153  auto acIt = wifiAcList.find (preferredAc);
1154  for (uint8_t i = 0; i < 4; i++)
1155  {
1156  NS_ASSERT (acIt != wifiAcList.end ());
1157  tids.push_back (acIt->second.GetHighTid ());
1158  tids.push_back (acIt->second.GetLowTid ());
1159 
1160  acIt++;
1161  if (acIt == wifiAcList.end ())
1162  {
1163  acIt = wifiAcList.begin ();
1164  }
1165  }
1166 
1168  Ptr<WifiPsdu> psdu;
1169  WifiTxParameters txParams;
1170  WifiTxVector tbTxVector = GetHeTbTxVector (trigger, hdr.GetAddr2 ());
1171  Time ppduDuration = HePhy::ConvertLSigLengthToHeTbPpduDuration (trigger.GetUlLength (),
1172  tbTxVector,
1173  m_phy->GetPhyBand ());
1174 
1175  for (const auto& tid : tids)
1176  {
1177  Ptr<QosTxop> edca = m_mac->GetQosTxop (tid);
1178 
1179  if (!edca->GetBaAgreementEstablished (hdr.GetAddr2 (), tid))
1180  {
1181  // no Block Ack agreement established for this TID
1182  continue;
1183  }
1184 
1185  txParams.Clear ();
1186  txParams.m_txVector = tbTxVector;
1187 
1188  // first, check if there is a pending BlockAckReq frame
1189  if ((mpdu = edca->GetBaManager ()->GetBar (false, tid, hdr.GetAddr2 ())) != 0
1190  && TryAddMpdu (mpdu, txParams, ppduDuration))
1191  {
1192  NS_LOG_DEBUG ("Sending a BAR within a TB PPDU");
1193  psdu = Create<WifiPsdu> (edca->GetBaManager ()->GetBar (true, tid, hdr.GetAddr2 ()), true);
1194  break;
1195  }
1196 
1197  // otherwise, check if a suitable data frame is available
1198  if ((mpdu = edca->PeekNextMpdu (tid, hdr.GetAddr2 ())) != 0)
1199  {
1201  Ptr<WifiMacQueueItem> item = edca->GetNextMpdu (mpdu, txParams, ppduDuration, false, queueIt);
1202 
1203  if (item != 0)
1204  {
1205  // try A-MPDU aggregation
1206  std::vector<Ptr<WifiMacQueueItem>> mpduList = m_mpduAggregator->GetNextAmpdu (item, txParams,
1207  ppduDuration,
1208  queueIt);
1209  psdu = (mpduList.size () > 1 ? Create<WifiPsdu> (std::move (mpduList))
1210  : Create<WifiPsdu> (item, true));
1211  break;
1212  }
1213  }
1214  }
1215 
1216  if (psdu != 0)
1217  {
1218  psdu->SetDuration (hdr.GetDuration () - m_phy->GetSifs () - ppduDuration);
1219  SendPsduMapWithProtection (WifiPsduMap {{staId, psdu}}, txParams);
1220  }
1221  else
1222  {
1223  // send QoS Null frames
1224  SendQosNullFramesInTbPpdu (trigger, hdr);
1225  }
1226 }
1227 
1228 void
1229 HeFrameExchangeManager::SendQosNullFramesInTbPpdu (const CtrlTriggerHeader& trigger, const WifiMacHeader& hdr)
1230 {
1231  NS_LOG_FUNCTION (this << trigger << hdr);
1232  NS_ASSERT (trigger.IsBasic () || trigger.IsBsrp ());
1233  NS_ASSERT (m_staMac != 0 && m_staMac->IsAssociated ());
1234 
1235  NS_LOG_DEBUG ("Requested to send QoS Null frames");
1236 
1237  if (trigger.GetCsRequired () && hdr.GetAddr2 () != m_txopHolder && m_navEnd > Simulator::Now ())
1238  {
1239  NS_LOG_DEBUG ("Carrier Sensing required and channel busy, do nothing");
1240  return;
1241  }
1242 
1243  WifiMacHeader header;
1244  header.SetType (WIFI_MAC_QOSDATA_NULL);
1245  header.SetAddr1 (hdr.GetAddr2 ());
1246  header.SetAddr2 (m_self);
1247  header.SetAddr3 (hdr.GetAddr2 ());
1248  header.SetDsTo ();
1249  header.SetDsNotFrom ();
1250  // TR3: Sequence numbers for transmitted QoS (+)Null frames may be set
1251  // to any value. (Table 10-3 of 802.11-2016)
1252  header.SetSequenceNumber (0);
1253  // Set the EOSP bit so that NotifyTxToEdca will add the Queue Size
1254  header.SetQosEosp ();
1255 
1256  WifiTxParameters txParams;
1257  txParams.m_txVector = GetHeTbTxVector (trigger, hdr.GetAddr2 ());
1258  txParams.m_protection = std::unique_ptr<WifiProtection> (new WifiNoProtection);
1259  txParams.m_acknowledgment = std::unique_ptr<WifiAcknowledgment> (new WifiNoAck);
1260 
1261  Time ppduDuration = HePhy::ConvertLSigLengthToHeTbPpduDuration (trigger.GetUlLength (),
1262  txParams.m_txVector,
1263  m_phy->GetPhyBand ());
1264  header.SetDuration (hdr.GetDuration () - m_phy->GetSifs () - ppduDuration);
1265 
1266  Ptr<WifiMacQueueItem> mpdu;
1267  std::vector<Ptr<WifiMacQueueItem>> mpduList;
1268  uint8_t tid = 0;
1269  header.SetQosTid (tid);
1270 
1271  while (tid < 8
1272  && IsWithinSizeAndTimeLimits (txParams.GetSizeIfAddMpdu (mpdu = Create<WifiMacQueueItem> (Create<Packet> (),
1273  header)),
1274  hdr.GetAddr2 (), txParams, ppduDuration))
1275  {
1276  NS_LOG_DEBUG ("Aggregating a QoS Null frame with tid=" << +tid);
1277  // We could call TryAddMpdu instead of IsWithinSizeAndTimeLimits above in order to
1278  // get the TX parameters updated automatically. However, aggregating the QoS Null
1279  // frames might fail because MPDU aggregation is disabled by default for VO
1280  // and BK. Therefore, we skip the check on max A-MPDU size and only update the
1281  // TX parameters below.
1282  txParams.m_acknowledgment = GetAckManager ()->TryAddMpdu (mpdu, txParams);
1283  txParams.AddMpdu (mpdu);
1284  UpdateTxDuration (mpdu->GetHeader ().GetAddr1 (), txParams);
1285  mpduList.push_back (mpdu);
1286  header.SetQosTid (++tid);
1287  }
1288 
1289  if (mpduList.empty ())
1290  {
1291  NS_LOG_DEBUG ("Not enough time to send a QoS Null frame");
1292  return;
1293  }
1294 
1295  Ptr<WifiPsdu> psdu = (mpduList.size () > 1 ? Create<WifiPsdu> (std::move (mpduList))
1296  : Create<WifiPsdu> (mpduList.front (), true));
1297  uint16_t staId = m_staMac->GetAssociationId ();
1298  SendPsduMapWithProtection (WifiPsduMap {{staId, psdu}}, txParams);
1299 }
1300 
1301 void
1302 HeFrameExchangeManager::ReceiveMpdu (Ptr<WifiMacQueueItem> mpdu, RxSignalInfo rxSignalInfo,
1303  const WifiTxVector& txVector, bool inAmpdu)
1304 {
1305  // The received MPDU is either broadcast or addressed to this station
1306  NS_ASSERT (mpdu->GetHeader ().GetAddr1 ().IsBroadcast ()
1307  || mpdu->GetHeader ().GetAddr1 () == m_self);
1308 
1309  const WifiMacHeader& hdr = mpdu->GetHeader ();
1310 
1311  if (txVector.IsUlMu () && m_txTimer.IsRunning ()
1312  && m_txTimer.GetReason () == WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF)
1313  {
1314  Mac48Address sender = hdr.GetAddr2 ();
1315  NS_ASSERT (m_txParams.m_acknowledgment
1316  && m_txParams.m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
1317  WifiUlMuMultiStaBa* acknowledgment = static_cast<WifiUlMuMultiStaBa*> (m_txParams.m_acknowledgment.get ());
1318  std::size_t index = acknowledgment->baType.m_bitmapLen.size ();
1319 
1320  if (m_staExpectTbPpduFrom.find (sender) == m_staExpectTbPpduFrom.end ())
1321  {
1322  NS_LOG_WARN ("Received a TB PPDU from an unexpected station: " << sender);
1323  return;
1324  }
1325 
1326  if (hdr.IsBlockAckReq ())
1327  {
1328  NS_LOG_DEBUG ("Received a BlockAckReq in a TB PPDU from " << sender);
1329 
1330  CtrlBAckRequestHeader blockAckReq;
1331  mpdu->GetPacket ()->PeekHeader (blockAckReq);
1332  NS_ABORT_MSG_IF (blockAckReq.IsMultiTid (), "Multi-TID BlockAckReq not supported");
1333  uint8_t tid = blockAckReq.GetTidInfo ();
1334  auto agreementIt = m_agreements.find ({sender, tid});
1335  NS_ASSERT (agreementIt != m_agreements.end ());
1336  agreementIt->second.NotifyReceivedBar (blockAckReq.GetStartingSequence ());
1337 
1338  // Block Acknowledgment context
1339  acknowledgment->stationsReceivingMultiStaBa.emplace (std::make_pair (sender, tid), index);
1340  acknowledgment->baType.m_bitmapLen.push_back (GetBlockAckType (sender, tid).m_bitmapLen.at (0));
1341  uint16_t staId = txVector.GetHeMuUserInfoMap ().begin ()->first;
1342  m_muSnrTag.Set (staId, rxSignalInfo.snr);
1343  }
1344  else if (hdr.IsQosData () && !inAmpdu && hdr.GetQosAckPolicy () == WifiMacHeader::NORMAL_ACK)
1345  {
1346  NS_LOG_DEBUG ("Received an S-MPDU in a TB PPDU from " << sender << " (" << *mpdu << ")");
1347 
1348  uint8_t tid = hdr.GetQosTid ();
1349  auto agreementIt = m_agreements.find ({sender, tid});
1350  NS_ASSERT (agreementIt != m_agreements.end ());
1351  agreementIt->second.NotifyReceivedMpdu (mpdu);
1352 
1353  // Acknowledgment context of Multi-STA Block Acks
1354  acknowledgment->stationsReceivingMultiStaBa.emplace (std::make_pair (sender, tid), index);
1355  acknowledgment->baType.m_bitmapLen.push_back (0);
1356  uint16_t staId = txVector.GetHeMuUserInfoMap ().begin ()->first;
1357  m_muSnrTag.Set (staId, rxSignalInfo.snr);
1358  }
1359  else if (!(hdr.IsQosData () && !hdr.HasData () && !inAmpdu))
1360  {
1361  // The other case handled by this function is when we receive a QoS Null frame
1362  // that is not in an A-MPDU. For all other cases, the reception is handled by
1363  // parent classes. In particular, in case of a QoS data frame in A-MPDU, we
1364  // have to wait until the A-MPDU reception is completed, but we let the
1365  // parent classes notify the Block Ack agreement of the reception of this MPDU
1366  VhtFrameExchangeManager::ReceiveMpdu (mpdu, rxSignalInfo, txVector, inAmpdu);
1367  return;
1368  }
1369 
1370  // Schedule the transmission of a Multi-STA BlockAck frame if needed
1371  if (!acknowledgment->stationsReceivingMultiStaBa.empty () && !m_multiStaBaEvent.IsRunning ())
1372  {
1373  m_multiStaBaEvent = Simulator::Schedule (m_phy->GetSifs (),
1374  &HeFrameExchangeManager::SendMultiStaBlockAck,
1375  this, std::cref (m_txParams));
1376  }
1377 
1378  // remove the sender from the set of stations that are expected to send a TB PPDU
1379  m_staExpectTbPpduFrom.erase (sender);
1380 
1381  if (m_staExpectTbPpduFrom.empty ())
1382  {
1383  // we do not expect any other BlockAck frame
1384  m_txTimer.Cancel ();
1385  m_channelAccessManager->NotifyAckTimeoutResetNow ();
1386 
1387  if (!m_multiStaBaEvent.IsRunning ())
1388  {
1389  // all of the stations that replied with a TB PPDU sent QoS Null frames.
1390  NS_LOG_DEBUG ("Continue the TXOP");
1391  m_psduMap.clear ();
1392  m_edca->ResetCw ();
1393  TransmissionSucceeded ();
1394  }
1395  }
1396 
1397  // the received TB PPDU has been processed
1398  return;
1399  }
1400 
1401  if (hdr.IsCtl ())
1402  {
1403  if (hdr.IsAck () && m_txTimer.IsRunning ()
1404  && m_txTimer.GetReason () == WifiTxTimer::WAIT_NORMAL_ACK_AFTER_DL_MU_PPDU)
1405  {
1406  NS_ASSERT (hdr.GetAddr1 () == m_self);
1407  NS_ASSERT (m_txParams.m_acknowledgment);
1408  NS_ASSERT (m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE);
1409 
1410  WifiDlMuBarBaSequence* acknowledgment = static_cast<WifiDlMuBarBaSequence*> (m_txParams.m_acknowledgment.get ());
1411  NS_ASSERT (acknowledgment->stationsReplyingWithNormalAck.size () == 1);
1412  NS_ASSERT (m_apMac != 0);
1413  uint16_t staId = m_apMac->GetAssociationId (acknowledgment->stationsReplyingWithNormalAck.begin ()->first);
1414  auto it = m_psduMap.find (staId);
1415  NS_ASSERT (it != m_psduMap.end ());
1416  NS_ASSERT (it->second->GetAddr1 () == acknowledgment->stationsReplyingWithNormalAck.begin ()->first);
1417  SnrTag tag;
1418  mpdu->GetPacket ()->PeekPacketTag (tag);
1419  ReceivedNormalAck (*it->second->begin (), m_txParams.m_txVector, txVector, rxSignalInfo, tag.Get ());
1420  }
1421  else if (hdr.IsBlockAck () && m_txTimer.IsRunning ()
1422  && m_txTimer.GetReason () == WifiTxTimer::WAIT_BLOCK_ACKS_IN_TB_PPDU)
1423  {
1424  Mac48Address sender = hdr.GetAddr2 ();
1425  NS_LOG_DEBUG ("Received BlockAck in TB PPDU from=" << sender);
1426 
1427  SnrTag tag;
1428  mpdu->GetPacket ()->PeekPacketTag (tag);
1429 
1430  // notify the Block Ack Manager
1431  CtrlBAckResponseHeader blockAck;
1432  mpdu->GetPacket ()->PeekHeader (blockAck);
1433  uint8_t tid = blockAck.GetTidInfo ();
1434  std::pair<uint16_t,uint16_t> ret = GetBaManager (tid)->NotifyGotBlockAck (blockAck, hdr.GetAddr2 (),
1435  {tid});
1436  m_mac->GetWifiRemoteStationManager ()->ReportAmpduTxStatus (hdr.GetAddr2 (), ret.first, ret.second,
1437  rxSignalInfo.snr, tag.Get (), m_txParams.m_txVector);
1438 
1439  // remove the sender from the set of stations that are expected to send a BlockAck
1440  if (m_staExpectTbPpduFrom.erase (sender) == 0)
1441  {
1442  NS_LOG_WARN ("Received a BlockAck from an unexpected stations: " << sender);
1443  return;
1444  }
1445 
1446  if (m_staExpectTbPpduFrom.empty ())
1447  {
1448  // we do not expect any other BlockAck frame
1449  m_txTimer.Cancel ();
1450  m_channelAccessManager->NotifyAckTimeoutResetNow ();
1451  m_triggerFrame = nullptr; // this is strictly needed for DL_MU_TF_MU_BAR only
1452 
1453  m_edca->ResetCw ();
1454  m_psduMap.clear ();
1455  TransmissionSucceeded ();
1456  }
1457  }
1458  else if (hdr.IsBlockAck () && m_txTimer.IsRunning ()
1459  && m_txTimer.GetReason () == WifiTxTimer::WAIT_BLOCK_ACK_AFTER_TB_PPDU)
1460  {
1461  CtrlBAckResponseHeader blockAck;
1462  mpdu->GetPacket ()->PeekHeader (blockAck);
1463 
1464  NS_ABORT_MSG_IF (!blockAck.IsMultiSta (),
1465  "A Multi-STA BlockAck is expected after a TB PPDU");
1466  NS_LOG_DEBUG ("Received a Multi-STA BlockAck from=" << hdr.GetAddr2 ());
1467 
1468  NS_ASSERT (m_staMac != nullptr && m_staMac->IsAssociated ());
1469  uint16_t staId = m_staMac->GetAssociationId ();
1470  std::vector<uint32_t> indices = blockAck.FindPerAidTidInfoWithAid (staId);
1471 
1472  if (indices.empty ())
1473  {
1474  NS_LOG_DEBUG ("No Per AID TID Info subfield intended for me");
1475  return;
1476  }
1477 
1478  MuSnrTag tag;
1479  mpdu->GetPacket ()->PeekPacketTag (tag);
1480 
1481  // notify the Block Ack Manager
1482  for (const auto& index : indices)
1483  {
1484  uint8_t tid = blockAck.GetTidInfo (index);
1485 
1486  if (blockAck.GetAckType (index) && tid < 8)
1487  {
1488  // Acknowledgment context
1489  NS_ABORT_IF (m_psduMap.empty () || m_psduMap.begin ()->first != staId);
1490  GetBaManager (tid)->NotifyGotAck (*m_psduMap.at (staId)->begin ());
1491  }
1492  else
1493  {
1494  // Block Acknowledgment or All-ack context
1495  if (blockAck.GetAckType (index) && tid == 14)
1496  {
1497  // All-ack context, we need to determine the actual TID(s) of the PSDU
1498  NS_ASSERT (indices.size () == 1);
1499  NS_ABORT_IF (m_psduMap.empty () || m_psduMap.begin ()->first != staId);
1500  std::set<uint8_t> tids = m_psduMap.at (staId)->GetTids ();
1501  NS_ABORT_MSG_IF (tids.size () > 1, "Multi-TID A-MPDUs not supported yet");
1502  tid = *tids.begin ();
1503  }
1504 
1505  std::pair<uint16_t,uint16_t> ret = GetBaManager (tid)->NotifyGotBlockAck (blockAck,
1506  hdr.GetAddr2 (),
1507  {tid}, index);
1508  m_mac->GetWifiRemoteStationManager ()->ReportAmpduTxStatus (hdr.GetAddr2 (), ret.first,
1509  ret.second, rxSignalInfo.snr,
1510  tag.Get (staId), m_txParams.m_txVector);
1511  }
1512 
1513  if (m_psduMap.at (staId)->GetHeader (0).IsQosData ()
1514  && (blockAck.GetAckType (index) // Ack or All-ack context
1515  || std::any_of (blockAck.GetBitmap (index).begin (),
1516  blockAck.GetBitmap (index).end (),
1517  [](uint8_t b) { return b != 0; })))
1518  {
1519  NS_ASSERT (m_psduMap.at (staId)->GetHeader (0).HasData ());
1520  NS_ASSERT (m_psduMap.at (staId)->GetHeader (0).GetQosTid () == tid);
1521  // the station has received a response from the AP for the HE TB PPDU
1522  // transmitted in response to a Basic Trigger Frame and at least one
1523  // MPDU was acknowledged. Therefore, it needs to update the access
1524  // parameters if it received an MU EDCA Parameter Set element.
1525  m_mac->GetQosTxop (tid)->StartMuEdcaTimerNow ();
1526  }
1527  }
1528 
1529  // cancel the timer
1530  m_txTimer.Cancel ();
1531  m_channelAccessManager->NotifyAckTimeoutResetNow ();
1532  m_psduMap.clear ();
1533  }
1534  else if (hdr.IsTrigger ())
1535  {
1536  // Trigger Frames are only processed by STAs
1537  if (m_staMac == nullptr)
1538  {
1539  return;
1540  }
1541 
1542  // A Trigger Frame in an A-MPDU is processed when the A-MPDU is fully received
1543  if (inAmpdu)
1544  {
1545  m_triggerFrameInAmpdu = true;
1546  return;
1547  }
1548 
1549  CtrlTriggerHeader trigger;
1550  mpdu->GetPacket ()->PeekHeader (trigger);
1551 
1552  if (hdr.GetAddr1 () != m_self
1553  && (!hdr.GetAddr1 ().IsBroadcast ()
1554  || !m_staMac->IsAssociated ()
1555  || hdr.GetAddr2 () != m_bssid // not sent by the AP this STA is associated with
1556  || trigger.FindUserInfoWithAid (m_staMac->GetAssociationId ()) == trigger.end ()))
1557  {
1558  // not addressed to us
1559  return;
1560  }
1561 
1562  uint16_t staId = m_staMac->GetAssociationId ();
1563 
1564  if (trigger.IsMuBar ())
1565  {
1566  Mac48Address sender = hdr.GetAddr2 ();
1567  NS_LOG_DEBUG ("Received MU-BAR Trigger Frame from=" << sender);
1568  m_mac->GetWifiRemoteStationManager ()->ReportRxOk (sender, rxSignalInfo, txVector);
1569 
1570  auto userInfoIt = trigger.FindUserInfoWithAid (staId);
1571  NS_ASSERT (userInfoIt != trigger.end ());
1572  CtrlBAckRequestHeader blockAckReq = userInfoIt->GetMuBarTriggerDepUserInfo ();
1573  NS_ABORT_MSG_IF (blockAckReq.IsMultiTid (), "Multi-TID BlockAckReq not supported");
1574  uint8_t tid = blockAckReq.GetTidInfo ();
1575 
1576  auto agreementIt = m_agreements.find ({sender, tid});
1577 
1578  if (agreementIt == m_agreements.end ())
1579  {
1580  NS_LOG_DEBUG ("There's not a valid agreement for this BlockAckReq");
1581  return;
1582  }
1583 
1584  agreementIt->second.NotifyReceivedBar (blockAckReq.GetStartingSequence ());
1585 
1586  NS_LOG_DEBUG ("Schedule Block Ack in TB PPDU");
1587  Simulator::Schedule (m_phy->GetSifs (), &HeFrameExchangeManager::SendBlockAck, this,
1588  agreementIt->second, hdr.GetDuration (),
1589  GetHeTbTxVector (trigger, hdr.GetAddr2 ()), rxSignalInfo.snr);
1590  }
1591  else if (trigger.IsBasic ())
1592  {
1593  Simulator::Schedule (m_phy->GetSifs (), &HeFrameExchangeManager::ReceiveBasicTrigger,
1594  this, trigger, hdr);
1595  }
1596  else if (trigger.IsBsrp ())
1597  {
1598  Simulator::Schedule (m_phy->GetSifs (), &HeFrameExchangeManager::SendQosNullFramesInTbPpdu,
1599  this, trigger, hdr);
1600  }
1601  }
1602  else
1603  {
1604  // the received control frame cannot be handled here
1605  VhtFrameExchangeManager::ReceiveMpdu (mpdu, rxSignalInfo, txVector, inAmpdu);
1606  }
1607 
1608  // the received control frame has been processed
1609  return;
1610  }
1611 
1612  // the received frame cannot be handled here
1613  VhtFrameExchangeManager::ReceiveMpdu (mpdu, rxSignalInfo, txVector, inAmpdu);;
1614 }
1615 
1616 void
1617 HeFrameExchangeManager::EndReceiveAmpdu (Ptr<const WifiPsdu> psdu, const RxSignalInfo& rxSignalInfo,
1618  const WifiTxVector& txVector, const std::vector<bool>& perMpduStatus)
1619 {
1620  std::set<uint8_t> tids = psdu->GetTids ();
1621 
1622  if (txVector.IsUlMu () && m_txTimer.IsRunning ()
1623  && m_txTimer.GetReason () == WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF)
1624  {
1625  Mac48Address sender = psdu->GetAddr2 ();
1626  NS_ASSERT (m_txParams.m_acknowledgment
1627  && m_txParams.m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
1628  WifiUlMuMultiStaBa* acknowledgment = static_cast<WifiUlMuMultiStaBa*> (m_txParams.m_acknowledgment.get ());
1629  std::size_t index = acknowledgment->baType.m_bitmapLen.size ();
1630 
1631  if (m_staExpectTbPpduFrom.find (sender) == m_staExpectTbPpduFrom.end ())
1632  {
1633  NS_LOG_WARN ("Received a TB PPDU from an unexpected station: " << sender);
1634  return;
1635  }
1636 
1637  NS_LOG_DEBUG ("Received an A-MPDU in a TB PPDU from " << sender << " (" << *psdu << ")");
1638 
1639  if (std::any_of (tids.begin (), tids.end (),
1640  [&psdu](uint8_t tid)
1641  { return psdu->GetAckPolicyForTid (tid) == WifiMacHeader::NORMAL_ACK; }))
1642  {
1643  if (std::all_of (perMpduStatus.cbegin (), perMpduStatus.cend (), [](bool v) { return v; }))
1644  {
1645  // All-ack context
1646  acknowledgment->stationsReceivingMultiStaBa.emplace (std::make_pair (sender, 14), index);
1647  acknowledgment->baType.m_bitmapLen.push_back (0);
1648  }
1649  else
1650  {
1651  // Block Acknowledgment context
1652  std::size_t i = 0;
1653  for (const auto& tid : tids)
1654  {
1655  acknowledgment->stationsReceivingMultiStaBa.emplace (std::make_pair (sender, tid), index + i++);
1656  acknowledgment->baType.m_bitmapLen.push_back (GetBlockAckType (sender, tid).m_bitmapLen.at (0));
1657  }
1658  }
1659  uint16_t staId = txVector.GetHeMuUserInfoMap ().begin ()->first;
1660  m_muSnrTag.Set (staId, rxSignalInfo.snr);
1661  }
1662 
1663  // Schedule the transmission of a Multi-STA BlockAck frame if needed
1664  if (!acknowledgment->stationsReceivingMultiStaBa.empty () && !m_multiStaBaEvent.IsRunning ())
1665  {
1666  m_multiStaBaEvent = Simulator::Schedule (m_phy->GetSifs (),
1667  &HeFrameExchangeManager::SendMultiStaBlockAck,
1668  this, std::cref (m_txParams));
1669  }
1670 
1671  // remove the sender from the set of stations that are expected to send a TB PPDU
1672  m_staExpectTbPpduFrom.erase (sender);
1673 
1674  if (m_staExpectTbPpduFrom.empty ())
1675  {
1676  // we do not expect any other BlockAck frame
1677  m_txTimer.Cancel ();
1678  m_channelAccessManager->NotifyAckTimeoutResetNow ();
1679 
1680  if (!m_multiStaBaEvent.IsRunning ())
1681  {
1682  // all of the stations that replied with a TB PPDU sent QoS Null frames.
1683  NS_LOG_DEBUG ("Continue the TXOP");
1684  m_psduMap.clear ();
1685  m_edca->ResetCw ();
1686  TransmissionSucceeded ();
1687  }
1688  }
1689 
1690  // the received TB PPDU has been processed
1691  return;
1692  }
1693 
1694  if (txVector.IsUlMu () && m_txTimer.IsRunning ()
1695  && m_txTimer.GetReason () == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF)
1696  {
1697  Mac48Address sender = psdu->GetAddr2 ();
1698 
1699  if (m_staExpectTbPpduFrom.find (sender) == m_staExpectTbPpduFrom.end ())
1700  {
1701  NS_LOG_WARN ("Received a TB PPDU from an unexpected station: " << sender);
1702  return;
1703  }
1704  if (std::none_of (psdu->begin (), psdu->end (), [](Ptr<WifiMacQueueItem> mpdu)
1705  { return mpdu->GetHeader ().IsQosData ()
1706  && !mpdu->GetHeader ().HasData ();
1707  }))
1708  {
1709  NS_LOG_WARN ("No QoS Null frame in the received PSDU");
1710  return;
1711  }
1712 
1713  NS_LOG_DEBUG ("Received QoS Null frames in a TB PPDU from " << sender);
1714 
1715  // remove the sender from the set of stations that are expected to send a TB PPDU
1716  m_staExpectTbPpduFrom.erase (sender);
1717 
1718  if (m_staExpectTbPpduFrom.empty ())
1719  {
1720  // we do not expect any other response
1721  m_txTimer.Cancel ();
1722  m_channelAccessManager->NotifyAckTimeoutResetNow ();
1723 
1724  NS_ASSERT (m_edca != 0);
1725  m_psduMap.clear ();
1726  m_edca->ResetCw ();
1727  TransmissionSucceeded ();
1728  }
1729 
1730  // the received TB PPDU has been processed
1731  return;
1732  }
1733 
1734  if (m_triggerFrameInAmpdu)
1735  {
1736  // the received A-MPDU contains a Trigger Frame. It is now time to handle it.
1737  auto psduIt = psdu->begin ();
1738  while (psduIt != psdu->end ())
1739  {
1740  if ((*psduIt)->GetHeader ().IsTrigger ())
1741  {
1742  ReceiveMpdu (*psduIt, rxSignalInfo, txVector, false);
1743  }
1744  psduIt++;
1745  }
1746 
1747  m_triggerFrameInAmpdu = false;
1748  return;
1749  }
1750 
1751  // the received frame cannot be handled here
1752  VhtFrameExchangeManager::EndReceiveAmpdu (psdu, rxSignalInfo, txVector, perMpduStatus);
1753 }
1754 
1755 } //namespace ns3
ns3::CtrlTriggerHeader::end
ConstIterator end(void) const
Get a const iterator indicating past-the-last User Info field in the list.
Definition: ctrl-headers.cc:2016
ns3::GetBlockAckSize
uint32_t GetBlockAckSize(BlockAckType type)
Return the total BlockAck size (including FCS trailer).
Definition: wifi-utils.cc:63
ns3::TypeId
a unique identifier for an interface.
Definition: type-id.h:59
NS_LOG_COMPONENT_DEFINE
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
ns3::MultiUserScheduler::DL_MU_TX
@ DL_MU_TX
Definition: multi-user-scheduler.h:66
ns3::WIFI_MAC_QOSDATA_NULL
@ WIFI_MAC_QOSDATA_NULL
Definition: wifi-mac-header.h:74
ns3::WifiUlMuMultiStaBa
WifiUlMuMultiStaBa specifies that a Basic Trigger Frame is being sent to solicit TB PPDUs that will b...
Definition: wifi-acknowledgment.h:306
ns3::HeFrameExchangeManager::m_psduMap
WifiPsduMap m_psduMap
the A-MPDU being transmitted
Definition: he-frame-exchange-manager.h:218
ns3::WifiAcknowledgment::acknowledgmentTime
Time acknowledgmentTime
time required by the acknowledgment method
Definition: wifi-acknowledgment.h:104
ns3::FrameExchangeManager::m_txTimer
WifiTxTimer m_txTimer
the timer set upon frame transmission
Definition: frame-exchange-manager.h:379
ns3::WifiTxVector::SetTxPowerLevel
void SetTxPowerLevel(uint8_t powerlevel)
Sets the selected transmission power level.
Definition: wifi-tx-vector.cc:242
NS_OBJECT_ENSURE_REGISTERED
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:45
NS_ASSERT
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:67
ns3::WifiNoProtection
WifiNoProtection specifies that no protection method is used.
Definition: wifi-protection.h:82
ns3::VhtFrameExchangeManager
VhtFrameExchangeManager handles the frame exchange sequences for VHT stations.
Definition: vht-frame-exchange-manager.h:35
ns3::WifiMacQueueItem::GetPacket
Ptr< const Packet > GetPacket(void) const
Get the packet stored in this item.
Definition: wifi-mac-queue-item.cc:59
ns3::WifiMacHeader::SetNoMoreFragments
void SetNoMoreFragments(void)
Un-set the More Fragment bit in the Frame Control Field.
Definition: wifi-mac-header.cc:322
ns3::FrameExchangeManager::m_phy
Ptr< WifiPhy > m_phy
the PHY layer on this station
Definition: frame-exchange-manager.h:385
ns3::WifiMacHeader::SetDuration
void SetDuration(Time duration)
Set the Duration/ID field with the given duration (Time object).
Definition: wifi-mac-header.cc:300
ns3::Packet::PeekHeader
uint32_t PeekHeader(Header &header) const
Deserialize but does not remove the header from the internal buffer.
Definition: packet.cc:290
ns3::WifiPsduMap
std::unordered_map< uint16_t, Ptr< WifiPsdu > > WifiPsduMap
Map of PSDUs indexed by STA-ID.
Definition: he-frame-exchange-manager.h:34
ns3::WifiMacHeader::IsAck
bool IsAck(void) const
Return true if the header is an Ack header.
Definition: wifi-mac-header.cc:663
ns3::WifiPsdu::GetAddr1
Mac48Address GetAddr1(void) const
Get the Receiver Address (RA), which is common to all the MPDUs.
Definition: wifi-psdu.cc:111
ns3::WifiAcknowledgment::NONE
@ NONE
Definition: wifi-acknowledgment.h:52
ns3::CtrlBAckResponseHeader::GetBitmap
const std::vector< uint8_t > & GetBitmap(std::size_t index=0) const
Return a const reference to the bitmap from the BlockAck response header.
Definition: ctrl-headers.cc:1052
ns3::WifiPsdu::GetPayload
Ptr< const Packet > GetPayload(std::size_t i) const
Get the payload of the i-th MPDU.
Definition: wifi-psdu.cc:278
ns3::WifiPhy::GetSlot
Time GetSlot(void) const
Return the slot duration for this PHY.
Definition: wifi-phy.cc:922
ns3::Packet::AddHeader
void AddHeader(const Header &header)
Add header to this packet.
Definition: packet.cc:256
ns3::WifiTxParameters::m_txDuration
Time m_txDuration
TX duration of the frame.
Definition: wifi-tx-parameters.h:65
ns3
Every class exported by the ns3 library is enclosed in the ns3 namespace.
ns3::HtFrameExchangeManager::StartFrameExchange
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...
Definition: ht-frame-exchange-manager.cc:334
ns3::HtFrameExchangeManager::SendMpduFromBaManager
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...
Definition: ht-frame-exchange-manager.cc:387
ns3::WifiPhy::CalculateTxDuration
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition: wifi-phy.cc:1610
ns3::WifiMacHeader::SetDsTo
void SetDsTo(void)
Set the To DS bit in the Frame Control field.
Definition: wifi-mac-header.cc:96
ns3::WifiDlMuBarBaSequence::stationsSendBlockAckReqTo
std::map< Mac48Address, BlockAckReqInfo > stationsSendBlockAckReqTo
Set of stations receiving a BlockAckReq frame and replying with a BlockAck frame.
Definition: wifi-acknowledgment.h:234
ns3::WifiMacHeader::SetSequenceNumber
void SetSequenceNumber(uint16_t seq)
Set the sequence number of the header.
Definition: wifi-mac-header.cc:312
ns3::QosTxop::GetBaAgreementEstablished
bool GetBaAgreementEstablished(Mac48Address address, uint8_t tid) const
Definition: qos-txop.cc:249
ns3::WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF
@ WAIT_TB_PPDU_AFTER_BASIC_TF
Definition: wifi-tx-timer.h:62
ns3::CtrlBAckRequestHeader
Headers for BlockAckRequest.
Definition: ctrl-headers.h:49
ns3::WifiPsdu::end
std::vector< Ptr< WifiMacQueueItem > >::const_iterator end(void) const
Return a const iterator to past-the-last MPDU.
Definition: wifi-psdu.cc:337
ns3::WifiMacHeader::IsTrigger
bool IsTrigger(void) const
Return true if the header is a Trigger header.
Definition: wifi-mac-header.cc:753
multi-user-scheduler.h
ns3::WifiAcknowledgment::ACK_AFTER_TB_PPDU
@ ACK_AFTER_TB_PPDU
Definition: wifi-acknowledgment.h:60
ns3::WifiTxTimer::IsRunning
bool IsRunning(void) const
Return true if the timer is running.
Definition: wifi-tx-timer.cc:94
ns3::HtFrameExchangeManager::DoDispose
void DoDispose() override
Destructor implementation.
Definition: ht-frame-exchange-manager.cc:66
ns3::WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF
@ WAIT_QOS_NULL_AFTER_BSRP_TF
Definition: wifi-tx-timer.h:63
ns3::WifiMacHeader::SetDsNotFrom
void SetDsNotFrom(void)
Un-set the From DS bit in the Frame Control field.
Definition: wifi-mac-header.cc:90
ns3::WifiDlMuTfMuBar::stationsReplyingWithBlockAck
std::map< Mac48Address, BlockAckInfo > stationsReplyingWithBlockAck
Set of stations replying with a BlockAck frame.
Definition: wifi-acknowledgment.h:262
ns3::WifiPhy::CalculatePhyPreambleAndHeaderDuration
static Time CalculatePhyPreambleAndHeaderDuration(const WifiTxVector &txVector)
Definition: wifi-phy.cc:1604
ns3::QosTxop::GetBaManager
Ptr< BlockAckManager > GetBaManager(void)
Get the Block Ack Manager associated with this QosTxop.
Definition: qos-txop.cc:243
ns3::CtrlTriggerHeader::IsMuBar
bool IsMuBar(void) const
Check if this is a MU-BAR Trigger frame.
Definition: ctrl-headers.cc:1780
NS_LOG_WARN
#define NS_LOG_WARN(msg)
Use NS_LOG to output a message of level LOG_WARN.
Definition: log.h:265
ns3::HeFrameExchangeManager::GetTypeId
static TypeId GetTypeId(void)
Get the type ID.
Definition: he-frame-exchange-manager.cc:44
ns3::CtrlBAckResponseHeader::GetStartingSequence
uint16_t GetStartingSequence(std::size_t index=0) const
For Block Ack variants other than Multi-STA Block Ack, get the starting sequence number.
Definition: ctrl-headers.cc:530
ns3::FrameExchangeManager::m_channelAccessManager
Ptr< ChannelAccessManager > m_channelAccessManager
the channel access manager
Definition: frame-exchange-manager.h:384
ns3::WifiTxVector::SetAggregation
void SetAggregation(bool aggregation)
Sets if PSDU contains A-MPDU.
Definition: wifi-tx-vector.cc:292
ns3::HtFrameExchangeManager::SetWifiMac
void SetWifiMac(const Ptr< RegularWifiMac > mac) override
Set the MAC layer to use.
Definition: ht-frame-exchange-manager.cc:78
ns3::WifiDlMuTfMuBar::barTypes
std::list< BlockAckReqType > barTypes
BAR types.
Definition: wifi-acknowledgment.h:263
ns3::WifiDlMuBarBaSequence::stationsReplyingWithBlockAck
std::map< Mac48Address, BlockAckInfo > stationsReplyingWithBlockAck
Set of stations replying with a BlockAck frame (no more than one)
Definition: wifi-acknowledgment.h:232
ns3::HeFrameExchangeManager::m_muScheduler
Ptr< MultiUserScheduler > m_muScheduler
Multi-user Scheduler (HE APs only)
Definition: he-frame-exchange-manager.h:220
ns3::Mac48Address
an EUI-48 address
Definition: mac48-address.h:44
ns3::HtFrameExchangeManager::ForwardPsduDown
virtual void ForwardPsduDown(Ptr< const WifiPsdu > psdu, WifiTxVector &txVector)
Forward a PSDU down to the PHY layer.
Definition: ht-frame-exchange-manager.cc:923
ns3::WifiDlMuAggregateTf
WifiDlMuAggregateTf specifies that a DL MU PPDU made of PSDUs including each a MU-BAR Trigger Frame i...
Definition: wifi-acknowledgment.h:277
ns3::QosTxop::PeekNextMpdu
Ptr< const WifiMacQueueItem > PeekNextMpdu(uint8_t tid=8, Mac48Address recipient=Mac48Address::GetBroadcast())
Peek the next frame to transmit to the given receiver and of the given TID from the block ack manager...
Definition: qos-txop.cc:357
ns3::WifiMacHeader::SetNoRetry
void SetNoRetry(void)
Un-set the Retry bit in the Frame Control field.
Definition: wifi-mac-header.cc:347
ns3::WifiTxVector
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
Definition: wifi-tx-vector.h:71
ns3::CtrlBAckRequestHeader::IsMultiTid
bool IsMultiTid(void) const
Check if the current Ack Policy has Multi-TID Block Ack.
Definition: ctrl-headers.cc:263
ns3::HeFrameExchangeManager::StartFrameExchange
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...
Definition: he-frame-exchange-manager.cc:109
ns3::WifiMacHeader::GetAddr1
Mac48Address GetAddr1(void) const
Return the address in the Address 1 field.
Definition: wifi-mac-header.cc:424
third.mac
mac
Definition: third.py:99
ns3::VhtFrameExchangeManager::GetWifiPsdu
Ptr< WifiPsdu > GetWifiPsdu(Ptr< WifiMacQueueItem > mpdu, const WifiTxVector &txVector) const override
Get a PSDU containing the given MPDU.
Definition: vht-frame-exchange-manager.cc:56
ns3::WifiMacHeader::SetAddr3
void SetAddr3(Mac48Address address)
Fill the Address 3 field with the given address.
Definition: wifi-mac-header.cc:120
ns3::WifiConstPsduMap
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
Definition: he-frame-exchange-manager.h:43
ns3::MuSnrTag
A tag to be attached to a response to a multi-user UL frame, that carries the SNR values with which t...
Definition: mu-snr-tag.h:36
ns3::Packet::PeekPacketTag
bool PeekPacketTag(Tag &tag) const
Search a matching tag and call Tag::Deserialize if it is found.
Definition: packet.cc:978
ns3::WifiTxParameters
This class stores the TX parameters (TX vector, protection mechanism, acknowledgment mechanism,...
Definition: wifi-tx-parameters.h:45
ns3::Simulator::Schedule
static EventId Schedule(Time const &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:557
he-phy.h
Declaration of ns3::HePhy class and ns3::HeSigAParameters struct.
ns3::HeFrameExchangeManager::GetSupportedBaBufferSize
uint16_t GetSupportedBaBufferSize(void) const override
Get the maximum supported buffer size for a Block Ack agreement.
Definition: he-frame-exchange-manager.cc:66
ns3::WifiMacQueueItem::GetHeader
const WifiMacHeader & GetHeader(void) const
Get the header stored in this item.
Definition: wifi-mac-queue-item.cc:65
ns3::CtrlBAckResponseHeader::SetTidInfo
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...
Definition: ctrl-headers.cc:477
ns3::WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE
@ DL_MU_BAR_BA_SEQUENCE
Definition: wifi-acknowledgment.h:56
ns3::PeekPointer
U * PeekPointer(const Ptr< U > &p)
Definition: ptr.h:415
ns3::TypeId::SetParent
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:923
ns3::MultiUserScheduler::SU_TX
@ SU_TX
Definition: multi-user-scheduler.h:65
ns3::WifiTxParameters::m_protection
std::unique_ptr< WifiProtection > m_protection
protection method
Definition: wifi-tx-parameters.h:63
ns3::MU_BAR_TRIGGER
@ MU_BAR_TRIGGER
Definition: ctrl-headers.h:564
ns3::WifiTxVector::IsUlMu
bool IsUlMu(void) const
Return true if this TX vector is used for an uplink multi-user transmission.
Definition: wifi-tx-vector.cc:382
ns3::HeFrameExchangeManager::m_apMac
Ptr< ApWifiMac > m_apMac
MAC pointer (null if not an AP)
Definition: he-frame-exchange-manager.h:201
ns3::WifiMacHeader::SetAddr1
void SetAddr1(Mac48Address address)
Fill the Address 1 field with the given address.
Definition: wifi-mac-header.cc:108
ns3::WifiTxTimer::WAIT_BLOCK_ACK_AFTER_TB_PPDU
@ WAIT_BLOCK_ACK_AFTER_TB_PPDU
Definition: wifi-tx-timer.h:64
ns3::GetAckSize
uint32_t GetAckSize(void)
Return the total Ack size (including FCS trailer).
Definition: wifi-utils.cc:55
ns3::WifiMacHeader
Implements the IEEE 802.11 MAC header.
Definition: wifi-mac-header.h:85
ns3::CtrlBAckResponseHeader::IsMultiSta
bool IsMultiSta(void) const
Check if the BlockAck frame variant is Multi-STA Block Ack.
Definition: ctrl-headers.cc:564
ns3::HeFrameExchangeManager::SendMpduFromBaManager
bool SendMpduFromBaManager(Ptr< QosTxop > edca, Time availableTime, bool initialFrame) override
If the Block Ack Manager associated with the given EDCA has a BlockAckReq frame to transmit (the dura...
Definition: he-frame-exchange-manager.cc:170
ns3::CtrlBAckResponseHeader::SetAid11
void SetAid11(uint16_t aid, std::size_t index)
For Multi-STA Block Acks, set the AID11 subfield of the Per AID TID Info subfield identified by the g...
Definition: ctrl-headers.cc:570
ns3::GetBlockAckRequestSize
uint32_t GetBlockAckRequestSize(BlockAckReqType type)
Return the total BlockAckRequest size (including FCS trailer).
Definition: wifi-utils.cc:73
ns3::HeFrameExchangeManager::PrepareMuBar
Ptr< WifiMacQueueItem > PrepareMuBar(const WifiTxVector &responseTxVector, std::map< uint16_t, CtrlBAckRequestHeader > recipients) const
Build a MU-BAR Trigger Frame starting from the TXVECTOR used to respond to the MU-BAR (in case of mul...
Definition: he-frame-exchange-manager.cc:607
ns3::Ptr
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:74
ns3::WifiMacQueueItem::ConstIterator
std::list< Ptr< WifiMacQueueItem > >::const_iterator ConstIterator
Const iterator typedef.
Definition: wifi-mac-queue-item.h:144
ns3::WifiTxVector::SetLength
void SetLength(uint16_t length)
Set the LENGTH field of the L-SIG.
Definition: wifi-tx-vector.cc:322
ns3::WifiMacHeader::IsBlockAckReq
bool IsBlockAckReq(void) const
Return true if the header is a BlockAckRequest header.
Definition: wifi-mac-header.cc:741
ns3::HeFrameExchangeManager::DoDispose
void DoDispose() override
Destructor implementation.
Definition: he-frame-exchange-manager.cc:85
ns3::WifiTxVector::GetModulationClass
WifiModulationClass GetModulationClass(void) const
Get the modulation class specified by this TXVECTOR.
Definition: wifi-tx-vector.cc:128
ns3::WifiAcknowledgment::UL_MU_MULTI_STA_BA
@ UL_MU_MULTI_STA_BA
Definition: wifi-acknowledgment.h:59
ns3::QosFrameExchangeManager::m_edca
Ptr< QosTxop > m_edca
the EDCAF that gained channel access
Definition: qos-frame-exchange-manager.h:159
ns3::HeFrameExchangeManager::SendPsduMap
void SendPsduMap(void)
Send the current PSDU map as a DL MU PPDU.
Definition: he-frame-exchange-manager.cc:258
ns3::WifiTxParameters::GetSizeIfAddMpdu
uint32_t GetSizeIfAddMpdu(Ptr< const WifiMacQueueItem > mpdu) const
Get the size in bytes of the frame in case the given MPDU is added.
Definition: wifi-tx-parameters.cc:147
ns3::Now
Time Now(void)
create an ns3::Time instance which contains the current simulation time.
Definition: simulator.cc:287
ns3::HeFrameExchangeManager::CalculateAcknowledgmentTime
void CalculateAcknowledgmentTime(WifiAcknowledgment *acknowledgment) const override
Calculate the time required to acknowledge a frame according to the given acknowledgment method.
Definition: he-frame-exchange-manager.cc:657
max
#define max(a, b)
Definition: 80211b.c:43
ns3::WifiProtection::NONE
@ NONE
Definition: wifi-protection.h:47
ns3::HeFrameExchangeManager::HeFrameExchangeManager
HeFrameExchangeManager()
Definition: he-frame-exchange-manager.cc:54
ns3::WifiTxTimer::WAIT_NORMAL_ACK_AFTER_DL_MU_PPDU
@ WAIT_NORMAL_ACK_AFTER_DL_MU_PPDU
Definition: wifi-tx-timer.h:60
ns3::CtrlBAckResponseHeader::SetAckType
void SetAckType(bool type, std::size_t index)
For Multi-STA Block Acks, set the Ack Type subfield of the Per AID TID Info subfield identified by th...
Definition: ctrl-headers.cc:586
ns3::WifiDlMuTfMuBar
WifiDlMuTfMuBar specifies that a DL MU PPDU is followed after a SIFS duration by a MU-BAR Trigger Fra...
Definition: wifi-acknowledgment.h:246
ns3::Mac48Address::IsBroadcast
bool IsBroadcast(void) const
Definition: mac48-address.cc:158
ns3::CtrlTriggerHeader::IsBasic
bool IsBasic(void) const
Check if this is a Basic Trigger frame.
Definition: ctrl-headers.cc:1768
ns3::HePhy::ConvertLSigLengthToHeTbPpduDuration
static Time ConvertLSigLengthToHeTbPpduDuration(uint16_t length, const WifiTxVector &txVector, WifiPhyBand band)
Definition: he-phy.cc:274
ns3::EventId::Cancel
void Cancel(void)
This method is syntactic sugar for the ns3::Simulator::Cancel method.
Definition: event-id.cc:53
ns3::WifiMacHeader::HasData
bool HasData(void) const
Return true if the header type is DATA and is not DATA_NULL.
Definition: wifi-mac-header.cc:632
ns3::CtrlTriggerHeader
Headers for Trigger frames.
Definition: ctrl-headers.h:886
ns3::MultiUserScheduler::UL_MU_TX
@ UL_MU_TX
Definition: multi-user-scheduler.h:67
ns3::WifiPsdu::GetSize
uint32_t GetSize(void) const
Return the size of the PSDU in bytes.
Definition: wifi-psdu.cc:260
ns3::WifiMacHeader::IsBlockAck
bool IsBlockAck(void) const
Return true if the header is a BlockAck header.
Definition: wifi-mac-header.cc:747
ns3::WifiDlMuTfMuBar::muBarTxVector
WifiTxVector muBarTxVector
TXVECTOR used to transmit the MU-BAR Trigger Frame.
Definition: wifi-acknowledgment.h:265
ns3::WifiTxVector::GetHeMuUserInfoMap
const HeMuUserInfoMap & GetHeMuUserInfoMap(void) const
Get a const reference to the map HE MU user-specific transmission information indexed by STA-ID.
Definition: wifi-tx-vector.cc:421
SU_STA_ID
#define SU_STA_ID
Definition: wifi-mode.h:32
ns3::WIFI_MAC_CTL_TRIGGER
@ WIFI_MAC_CTL_TRIGGER
Definition: wifi-mac-header.h:38
ns3::WifiTxParameters::Clear
void Clear(void)
Reset the TX parameters.
Definition: wifi-tx-parameters.cc:67
ns3::Copy
Ptr< T > Copy(Ptr< T > object)
Return a deep copy of a Ptr.
Definition: ptr.h:555
ns3::WifiPsdu::GetNMpdus
std::size_t GetNMpdus(void) const
Return the number of MPDUs constituting the PSDU.
Definition: wifi-psdu.cc:319
ns3::WifiMacHeader::IsQosData
bool IsQosData(void) const
Return true if the Type is DATA and Subtype is one of the possible values for QoS Data.
Definition: wifi-mac-header.cc:565
ns3::WifiPhy::GetPhyBand
WifiPhyBand GetPhyBand(void) const
Get the configured Wi-Fi band.
Definition: wifi-phy.cc:1124
ns3::WifiUlMuMultiStaBa::tbPpduTxVector
WifiTxVector tbPpduTxVector
TXVECTOR for a TB PPDU.
Definition: wifi-acknowledgment.h:316
ns3::WifiPsdu::GetTids
std::set< uint8_t > GetTids(void) const
Get the set of TIDs of the QoS Data frames included in the PSDU.
Definition: wifi-psdu.cc:166
ns3::Time
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:104
ns3::WifiDlMuTfMuBar::ulLength
uint16_t ulLength
the UL Length field of the MU-BAR Trigger Frame
Definition: wifi-acknowledgment.h:264
ns3::WifiTxTimer::WAIT_BLOCK_ACK
@ WAIT_BLOCK_ACK
Definition: wifi-tx-timer.h:59
ns3::WifiAcknowledgment::DL_MU_AGGREGATE_TF
@ DL_MU_AGGREGATE_TF
Definition: wifi-acknowledgment.h:58
NS_ABORT_MSG_IF
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
ns3::WifiPsdu::SetDuration
void SetDuration(Time duration)
Set the Duration/ID field on all the MPDUs.
Definition: wifi-psdu.cc:156
NS_ASSERT_MSG
#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:88
ns3::CtrlTriggerHeader::GetApTxPower
int8_t GetApTxPower(void) const
Get the power value (dBm) indicated by the AP TX Power subfield of the Common Info field.
Definition: ctrl-headers.cc:1966
ns3::CtrlTriggerHeader::GetUlLength
uint16_t GetUlLength(void) const
Get the UL Length subfield of the Common Info field.
Definition: ctrl-headers.cc:1822
ns3::BlockAckType::m_bitmapLen
std::vector< uint8_t > m_bitmapLen
Length (bytes) of included bitmaps.
Definition: block-ack-type.h:48
ns3::HeFrameExchangeManager::m_multiStaBaEvent
EventId m_multiStaBaEvent
Sending a Multi-STA BlockAck event.
Definition: he-frame-exchange-manager.h:223
ns3::WifiMacHeader::GetQosAckPolicy
QosAckPolicy GetQosAckPolicy(void) const
Return the QoS Ack policy in the QoS control field.
Definition: wifi-mac-header.cc:829
ns3::WifiTxTimer::Reason
Reason
The reason why the timer was started.
Definition: wifi-tx-timer.h:55
ns3::WifiTxVector::IsMu
bool IsMu(void) const
Return true if this TX vector is used for a multi-user transmission.
Definition: wifi-tx-vector.cc:370
ns3::MuSnrTag::Get
double Get(uint16_t staId) const
Return the SNR value for the given sender.
Definition: mu-snr-tag.cc:67
ns3::WifiTxParameters::m_acknowledgment
std::unique_ptr< WifiAcknowledgment > m_acknowledgment
acknowledgment method
Definition: wifi-tx-parameters.h:64
ns3::SnrTag
Introspection did not find any typical Config paths.
Definition: snr-tag.h:35
ns3::WifiDlMuAggregateTf::stationsReplyingWithBlockAck
std::map< Mac48Address, BlockAckInfo > stationsReplyingWithBlockAck
Set of stations replying with a BlockAck frame.
Definition: wifi-acknowledgment.h:294
ns3::QosTxop::PrepareBlockAckRequest
Ptr< const WifiMacQueueItem > PrepareBlockAckRequest(Mac48Address recipient, uint8_t tid) const
Definition: qos-txop.cc:267
ns3::wifiAcList
const std::map< AcIndex, WifiAc > wifiAcList
Map containing the four ACs in increasing order of priority (according to Table 10-1 "UP-to-AC Mappin...
Definition: qos-utils.cc:120
NS_LOG_LOGIC
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:289
ns3::WifiDlMuBarBaSequence
WifiDlMuBarBaSequence specifies that a DL MU PPDU is acknowledged through a sequence of BlockAckReq a...
Definition: wifi-acknowledgment.h:202
NS_ABORT_IF
#define NS_ABORT_IF(cond)
Abnormal program termination if a condition is true.
Definition: abort.h:77
ns3::CtrlBAckResponseHeader::SetType
void SetType(BlockAckType type)
Set the block ack type.
Definition: ctrl-headers.cc:456
ns3::WifiAckManager::SetQosAckPolicy
static void SetQosAckPolicy(Ptr< WifiMacQueueItem > item, const WifiAcknowledgment *acknowledgment)
Set the QoS Ack policy for the given MPDU, which must be a QoS data frame.
Definition: wifi-ack-manager.cc:64
ns3::Packet::AddPacketTag
void AddPacketTag(const Tag &tag) const
Add a packet tag.
Definition: packet.cc:956
ns3::WifiMacHeader::SetAddr2
void SetAddr2(Mac48Address address)
Fill the Address 2 field with the given address.
Definition: wifi-mac-header.cc:114
ns3::WifiMacHeader::GetQosTid
uint8_t GetQosTid(void) const
Return the Traffic ID of a QoS header.
Definition: wifi-mac-header.cc:862
ns3::WifiUlMuMultiStaBa::baType
BlockAckType baType
BlockAck type.
Definition: wifi-acknowledgment.h:315
NS_LOG_FUNCTION_NOARGS
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
Definition: log-macros-enabled.h:209
ns3::CtrlBAckResponseHeader::GetAckType
bool GetAckType(std::size_t index) const
For Multi-STA Block Acks, get the Ack Type subfield of the Per AID TID Info subfield identified by th...
Definition: ctrl-headers.cc:597
ns3::HtFrameExchangeManager::TransmissionSucceeded
void TransmissionSucceeded(void) override
Take necessary actions upon a transmission success.
Definition: ht-frame-exchange-manager.cc:580
ns3::Time::Min
static Time Min()
Minimum representable Time Not to be confused with Min(Time,Time).
Definition: nstime.h:274
ns3::CtrlBAckResponseHeader::GetTidInfo
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...
Definition: ctrl-headers.cc:510
timeout
ns3::Time timeout
Definition: openflow-switch.cc:52
he-frame-exchange-manager.h
ns3::WifiPsdu::GetAddr2
Mac48Address GetAddr2(void) const
Get the Transmitter Address (TA), which is common to all the MPDUs.
Definition: wifi-psdu.cc:126
ns3::RxSignalInfo::snr
double snr
SNR in linear scale.
Definition: phy-entity.h:68
ns3::HeFrameExchangeManager::BlockAckAfterTbPpduTimeout
virtual void BlockAckAfterTbPpduTimeout(Ptr< WifiPsdu > psdu, const WifiTxVector &txVector)
Take the necessary actions after that a Block Ack is missing after a TB PPDU solicited through a Trig...
Definition: he-frame-exchange-manager.cc:943
NS_LOG_DEBUG
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:273
ns3::WifiTxParameters::m_txVector
WifiTxVector m_txVector
TXVECTOR of the frame being prepared.
Definition: wifi-tx-parameters.h:62
ns3::HeFrameExchangeManager::SetWifiMac
void SetWifiMac(const Ptr< RegularWifiMac > mac) override
Set the MAC layer to use.
Definition: he-frame-exchange-manager.cc:77
ns3::QosTxop::GetNextMpdu
Ptr< WifiMacQueueItem > GetNextMpdu(Ptr< const WifiMacQueueItem > peekedItem, WifiTxParameters &txParams, Time availableTime, bool initialFrame, WifiMacQueueItem::ConstIterator &queueIt)
Prepare the frame to transmit starting from the MPDU that has been previously peeked by calling PeekN...
Definition: qos-txop.cc:443
ns3::CtrlTriggerHeader::GetCsRequired
bool GetCsRequired(void) const
Get the CS Required subfield of the Common Info field.
Definition: ctrl-headers.cc:1863
ns3::RxSignalInfo
RxSignalInfo structure containing info on the received signal.
Definition: phy-entity.h:67
ns3::Seconds
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1289
ns3::WifiAcknowledgment
WifiAcknowledgment is an abstract base struct.
Definition: wifi-acknowledgment.h:45
ns3::WifiTxVector::SetHeMuUserInfo
void SetHeMuUserInfo(uint16_t staId, HeMuUserInfo userInfo)
Set the HE MU user-specific transmission information for the given STA-ID.
Definition: wifi-tx-vector.cc:411
ns3::WifiNoAck
WifiNoAck specifies that no acknowledgment is required.
Definition: wifi-acknowledgment.h:130
ns3::FrameExchangeManager::m_mac
Ptr< RegularWifiMac > m_mac
the MAC layer on this station
Definition: frame-exchange-manager.h:381
ns3::WifiUlMuMultiStaBa::multiStaBaTxVector
WifiTxVector multiStaBaTxVector
TXVECTOR for the Multi-STA BlockAck.
Definition: wifi-acknowledgment.h:317
ns3::SnrTag::Get
double Get(void) const
Return the SNR value.
Definition: snr-tag.cc:89
ns3::AcIndex
AcIndex
This enumeration defines the Access Categories as an enumeration with values corresponding to the AC ...
Definition: qos-utils.h:71
NS_LOG_FUNCTION
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
Definition: log-macros-enabled.h:244
ns3::WifiDlMuBarBaSequence::stationsReplyingWithNormalAck
std::map< Mac48Address, AckInfo > stationsReplyingWithNormalAck
Set of stations replying with an Ack frame (no more than one)
Definition: wifi-acknowledgment.h:230
ns3::CtrlTriggerHeader::IsBsrp
bool IsBsrp(void) const
Check if this is a Buffer Status Report Poll Trigger frame.
Definition: ctrl-headers.cc:1792
ns3::WifiMacHeader::GetDuration
Time GetDuration(void) const
Return the duration from the Duration/ID field (Time object).
Definition: wifi-mac-header.cc:765
ns3::CtrlTriggerHeader::SetApTxPower
void SetApTxPower(int8_t power)
Set the AP TX Power subfield of the Common Info field.
Definition: ctrl-headers.cc:1957
ns3::QosTxop::ScheduleBar
void ScheduleBar(Ptr< const WifiMacQueueItem > bar, bool skipIfNoDataQueued=false)
Definition: qos-txop.cc:289
ns3::HeFrameExchangeManager::m_txParams
WifiTxParameters m_txParams
the TX parameters for the current PPDU
Definition: he-frame-exchange-manager.h:219
ns3::WifiMacHeader::SetQosEosp
void SetQosEosp()
Set the end of service period (EOSP) bit in the QoS control field.
Definition: wifi-mac-header.cc:357
ns3::WifiMacHeader::IsCtl
bool IsCtl(void) const
Return true if the Type is Control.
Definition: wifi-mac-header.cc:571
ns3::WifiTxTimer::WAIT_BLOCK_ACKS_IN_TB_PPDU
@ WAIT_BLOCK_ACKS_IN_TB_PPDU
Definition: wifi-tx-timer.h:61
ns3::WifiMacHeader::SetType
void SetType(WifiMacType type, bool resetToDsFromDs=true)
Set Type/Subtype values with the correct values depending on the given type.
Definition: wifi-mac-header.cc:132
ns3::HeFrameExchangeManager::SendPsduMapWithProtection
void SendPsduMapWithProtection(WifiPsduMap psduMap, WifiTxParameters &txParams)
Send a map of PSDUs as a DL MU PPDU.
Definition: he-frame-exchange-manager.cc:197
ns3::TracedValueCallback::Time
void(* Time)(Time oldValue, Time newValue)
TracedValue callback signature for Time.
Definition: nstime.h:813
ns3::WifiUlMuMultiStaBa::stationsReceivingMultiStaBa
std::map< std::pair< Mac48Address, uint8_t >, std::size_t > stationsReceivingMultiStaBa
Map (originator, tid) pairs to the their index in baType.
Definition: wifi-acknowledgment.h:314
he-configuration.h
ns3::WifiTxTimer::NOT_RUNNING
@ NOT_RUNNING
Definition: wifi-tx-timer.h:56
ns3::WifiTxParameters::AddMpdu
void AddMpdu(Ptr< const WifiMacQueueItem > mpdu)
Record that an MPDU is being added to the current frame.
Definition: wifi-tx-parameters.cc:98
ns3::WifiMacHeader::SetDsNotTo
void SetDsNotTo(void)
Un-set the To DS bit in the Frame Control field.
Definition: wifi-mac-header.cc:102
ns3::WifiAcknowledgment::DL_MU_TF_MU_BAR
@ DL_MU_TF_MU_BAR
Definition: wifi-acknowledgment.h:57
ns3::MultiUserScheduler::TxFormat
TxFormat
Enumeration of the possible transmission formats.
Definition: multi-user-scheduler.h:63
ns3::WifiTxVector::SetBssColor
void SetBssColor(uint8_t color)
Set the BSS color.
Definition: wifi-tx-vector.cc:310
ns3::WIFI_MAC_CTL_BACKRESP
@ WIFI_MAC_CTL_BACKRESP
Definition: wifi-mac-header.h:44
ns3::WIFI_MOD_CLASS_VHT
@ WIFI_MOD_CLASS_VHT
VHT (Clause 22)
Definition: wifi-phy-common.h:131
ns3::WifiPsdu::begin
std::vector< Ptr< WifiMacQueueItem > >::const_iterator begin(void) const
Return a const iterator to the first MPDU.
Definition: wifi-psdu.cc:325
ns3::CtrlBAckRequestHeader::GetStartingSequence
uint16_t GetStartingSequence(void) const
Return the starting sequence number.
Definition: ctrl-headers.cc:239
ns3::HeFrameExchangeManager::m_staMac
Ptr< StaWifiMac > m_staMac
MAC pointer (null if not a STA)
Definition: he-frame-exchange-manager.h:202
ns3::WifiAcknowledgment::method
const Method method
acknowledgment method
Definition: wifi-acknowledgment.h:103
ns3::HeFrameExchangeManager::GetPsduTo
static Ptr< WifiPsdu > GetPsduTo(Mac48Address to, const WifiPsduMap &psduMap)
Get the PSDU in the given PSDU map that is addressed to the given MAC address, if any,...
Definition: he-frame-exchange-manager.cc:245
ns3::HeFrameExchangeManager::~HeFrameExchangeManager
virtual ~HeFrameExchangeManager()
Definition: he-frame-exchange-manager.cc:60
ns3::WifiMacHeader::SetQosTid
void SetQosTid(uint8_t tid)
Set the TID for the QoS header.
Definition: wifi-mac-header.cc:352
ns3::GetMuBarSize
uint32_t GetMuBarSize(std::list< BlockAckReqType > types)
Return the total MU-BAR size (including FCS trailer).
Definition: wifi-utils.cc:83
ns3::CtrlBAckResponseHeader::FindPerAidTidInfoWithAid
std::vector< uint32_t > FindPerAidTidInfoWithAid(uint16_t aid) const
For Multi-STA Block Acks, get the indices of the Per AID TID Info subfields carrying the given AID in...
Definition: ctrl-headers.cc:628
ns3::WifiMacHeader::GetAddr2
Mac48Address GetAddr2(void) const
Return the address in the Address 2 field.
Definition: wifi-mac-header.cc:430
ns3::WifiPhy::GetSifs
Time GetSifs(void) const
Return the Short Interframe Space (SIFS) for this PHY.
Definition: wifi-phy.cc:910
ns3::WifiTxTimer::Set
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.
Definition: wifi-tx-timer.h:241
ns3::HeFrameExchangeManager::m_staExpectTbPpduFrom
std::set< Mac48Address > m_staExpectTbPpduFrom
set of stations expected to send a TB PPDU
Definition: he-frame-exchange-manager.h:222
ns3::HeFrameExchangeManager::TbPpduTimeout
virtual void TbPpduTimeout(WifiPsduMap *psduMap, const std::set< Mac48Address > *staMissedTbPpduFrom, std::size_t nSolicitedStations)
Take the necessary actions after that some TB PPDUs are missing in response to Trigger Frame.
Definition: he-frame-exchange-manager.cc:844
ns3::CtrlTriggerHeader::FindUserInfoWithAid
ConstIterator FindUserInfoWithAid(ConstIterator start, uint16_t aid12) const
Get a const iterator pointing to the first User Info field found (starting from the one pointed to by...
Definition: ctrl-headers.cc:2040
ns3::HeFrameExchangeManager::BlockAcksInTbPpduTimeout
virtual void BlockAcksInTbPpduTimeout(WifiPsduMap *psduMap, const std::set< Mac48Address > *staMissedBlockAckFrom, std::size_t nSolicitedStations)
Take the necessary actions after that some BlockAck frames are missing in response to a DL MU PPDU.
Definition: he-frame-exchange-manager.cc:875
ns3::WifiTxVector::IsDlMu
bool IsDlMu(void) const
Return true if this TX vector is used for a downlink multi-user transmission.
Definition: wifi-tx-vector.cc:376
ns3::HtFrameExchangeManager::GetPsduDurationId
virtual Time GetPsduDurationId(Time txDuration, const WifiTxParameters &txParams) const
Compute how to set the Duration/ID field of PSDUs that do not include fragments.
Definition: ht-frame-exchange-manager.cc:686
ns3::WifiDlMuAggregateTf::ulLength
uint16_t ulLength
the UL Length field of the MU-BAR Trigger Frames
Definition: wifi-acknowledgment.h:295
ns3::CtrlTriggerHeader::GetHeTbTxVector
WifiTxVector GetHeTbTxVector(uint16_t staId) const
Get the TX vector that the station with the given STA-ID will use to send the HE TB PPDU solicited by...
Definition: ctrl-headers.cc:1828
ns3::HeFrameExchangeManager::m_triggerFrame
Ptr< WifiMacQueueItem > m_triggerFrame
Trigger Frame being sent.
Definition: he-frame-exchange-manager.h:221
ns3::CtrlBAckRequestHeader::GetTidInfo
uint8_t GetTidInfo(void) const
Return the Traffic ID (TID).
Definition: ctrl-headers.cc:232
ns3::CtrlBAckResponseHeader
Headers for BlockAck response.
Definition: ctrl-headers.h:202
ns3::HtFrameExchangeManager::BlockAckTimeout
virtual void BlockAckTimeout(Ptr< WifiPsdu > psdu, const WifiTxVector &txVector)
Called when the BlockAck timeout expires.
Definition: ht-frame-exchange-manager.cc:1125
ns3::FrameExchangeManager::NormalAckTimeout
void NormalAckTimeout(Ptr< WifiMacQueueItem > mpdu, const WifiTxVector &txVector)
Called when the Ack timeout expires.
Definition: frame-exchange-manager.cc:770
ns3::HeFrameExchangeManager::SetMultiUserScheduler
void SetMultiUserScheduler(const Ptr< MultiUserScheduler > muScheduler)
Set the Multi-user Scheduler associated with this Frame Exchange Manager.
Definition: he-frame-exchange-manager.cc:98
NS_ABORT_MSG
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition: abort.h:50