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