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