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  // the PSDU is about to be transmitted, we can now dequeue the MPDUs
598  DequeuePsdu (psdu.second);
599  }
600  if (psduMap.size () > 1 || psduMap.begin ()->second->IsAggregate () || psduMap.begin ()->second->IsSingle ())
601  {
602  txVector.SetAggregation (true);
603  }
604 
605  m_phy->Send (psduMap, txVector);
606 }
607 
609 HeFrameExchangeManager::PrepareMuBar (const WifiTxVector& responseTxVector,
610  std::map<uint16_t, CtrlBAckRequestHeader> recipients) const
611 {
612  NS_LOG_FUNCTION (this << responseTxVector);
613  NS_ASSERT (responseTxVector.GetHeMuUserInfoMap ().size () == recipients.size ());
614  NS_ASSERT (!recipients.empty ());
615 
616  CtrlTriggerHeader muBar (TriggerFrameType::MU_BAR_TRIGGER, responseTxVector);
617  SetTargetRssi (muBar);
618  Mac48Address rxAddress;
619 
620  // Add the Trigger Dependent User Info subfield to every User Info field
621  for (auto& userInfo : muBar)
622  {
623  auto recipientIt = recipients.find (userInfo.GetAid12 ());
624  NS_ASSERT (recipientIt != recipients.end ());
625 
626  // Store the BAR in the Trigger Dependent User Info subfield
627  userInfo.SetMuBarTriggerDepUserInfo (recipientIt->second);
628  }
629 
630  Ptr<Packet> bar = Create<Packet> ();
631  bar->AddHeader (muBar);
632  // "If the Trigger frame has one User Info field and the AID12 subfield of the
633  // User Info contains the AID of a STA, then the RA field is set to the address
634  // of that STA". Otherwise, it is set to the broadcast address (Sec. 9.3.1.23 -
635  // 802.11ax amendment draft 3.0)
636  if (muBar.GetNUserInfoFields () > 1)
637  {
638  rxAddress = Mac48Address::GetBroadcast ();
639  }
640  else
641  {
642  NS_ASSERT (m_apMac != 0);
643  rxAddress = m_apMac->GetStaList ().at (recipients.begin ()->first);
644  }
645 
646  WifiMacHeader hdr;
648  hdr.SetAddr1 (rxAddress);
649  hdr.SetAddr2 (m_self);
650  hdr.SetDsNotTo ();
651  hdr.SetDsNotFrom ();
652  hdr.SetNoRetry ();
653  hdr.SetNoMoreFragments ();
654 
655  return Create<WifiMacQueueItem> (bar, hdr);
656 }
657 
658 void
659 HeFrameExchangeManager::CalculateAcknowledgmentTime (WifiAcknowledgment* acknowledgment) const
660 {
661  NS_LOG_FUNCTION (this << acknowledgment);
662  NS_ASSERT (acknowledgment != nullptr);
663 
664  /*
665  * Acknowledgment via a sequence of BlockAckReq and BlockAck frames
666  */
667  if (acknowledgment->method == WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE)
668  {
669  WifiDlMuBarBaSequence* dlMuBarBaAcknowledgment = static_cast<WifiDlMuBarBaSequence*> (acknowledgment);
670 
671  Time duration = Seconds (0);
672 
673  // normal ack or implicit BAR policy can be used for (no more than) one receiver
674  NS_ABORT_IF (dlMuBarBaAcknowledgment->stationsReplyingWithNormalAck.size ()
675  + dlMuBarBaAcknowledgment->stationsReplyingWithBlockAck.size () > 1);
676 
677  if (!dlMuBarBaAcknowledgment->stationsReplyingWithNormalAck.empty ())
678  {
679  const auto& info = dlMuBarBaAcknowledgment->stationsReplyingWithNormalAck.begin ()->second;
680  duration += m_phy->GetSifs ()
681  + m_phy->CalculateTxDuration (GetAckSize (), info.ackTxVector, m_phy->GetPhyBand ());
682  }
683 
684  if (!dlMuBarBaAcknowledgment->stationsReplyingWithBlockAck.empty ())
685  {
686  const auto& info = dlMuBarBaAcknowledgment->stationsReplyingWithBlockAck.begin ()->second;
687  duration += m_phy->GetSifs ()
688  + m_phy->CalculateTxDuration (GetBlockAckSize (info.baType),
689  info.blockAckTxVector, m_phy->GetPhyBand ());
690  }
691 
692  for (const auto& stations : dlMuBarBaAcknowledgment->stationsSendBlockAckReqTo)
693  {
694  const auto& info = stations.second;
695  duration += m_phy->GetSifs ()
696  + m_phy->CalculateTxDuration (GetBlockAckRequestSize (info.barType),
697  info.blockAckReqTxVector, m_phy->GetPhyBand ())
698  + m_phy->GetSifs ()
699  + m_phy->CalculateTxDuration (GetBlockAckSize (info.baType),
700  info.blockAckTxVector, m_phy->GetPhyBand ());
701  }
702 
703  dlMuBarBaAcknowledgment->acknowledgmentTime = duration;
704  }
705  /*
706  * Acknowledgment via a MU-BAR Trigger Frame sent as single user frame
707  */
708  else if (acknowledgment->method == WifiAcknowledgment::DL_MU_TF_MU_BAR)
709  {
710  WifiDlMuTfMuBar* dlMuTfMuBarAcknowledgment = static_cast<WifiDlMuTfMuBar*> (acknowledgment);
711 
712  Time duration = Seconds (0);
713 
714  for (const auto& stations : dlMuTfMuBarAcknowledgment->stationsReplyingWithBlockAck)
715  {
716  // compute the TX duration of the BlockAck response from this receiver.
717  const auto& info = stations.second;
718  NS_ASSERT (info.blockAckTxVector.GetHeMuUserInfoMap ().size () == 1);
719  uint16_t staId = info.blockAckTxVector.GetHeMuUserInfoMap ().begin ()->first;
720  Time currBlockAckDuration = m_phy->CalculateTxDuration (GetBlockAckSize (info.baType),
721  info.blockAckTxVector,
722  m_phy->GetPhyBand (),
723  staId);
724  // update the max duration among all the Block Ack responses
725  if (currBlockAckDuration > duration)
726  {
727  duration = currBlockAckDuration;
728  }
729  }
730 
731  // The computed duration may not be coded exactly in the L-SIG length, hence determine
732  // the exact duration corresponding to the value that will be coded in this field.
733  dlMuTfMuBarAcknowledgment->ulLength = HePhy::ConvertHeTbPpduDurationToLSigLength (duration, m_phy->GetPhyBand ());
734  WifiTxVector& txVector = dlMuTfMuBarAcknowledgment->stationsReplyingWithBlockAck.begin ()->second.blockAckTxVector;
735  duration = HePhy::ConvertLSigLengthToHeTbPpduDuration (dlMuTfMuBarAcknowledgment->ulLength,
736  txVector, m_phy->GetPhyBand ());
737 
738  uint32_t muBarSize = GetMuBarSize (dlMuTfMuBarAcknowledgment->barTypes);
739  dlMuTfMuBarAcknowledgment->acknowledgmentTime = m_phy->GetSifs ()
740  + m_phy->CalculateTxDuration (muBarSize,
741  dlMuTfMuBarAcknowledgment->muBarTxVector,
742  m_phy->GetPhyBand ())
743  + m_phy->GetSifs () + duration;
744  }
745  /*
746  * Acknowledgment requested by MU-BAR TFs aggregated to PSDUs in the DL MU PPDU
747  */
748  else if (acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF)
749  {
750  WifiDlMuAggregateTf* dlMuAggrTfAcknowledgment = static_cast<WifiDlMuAggregateTf*> (acknowledgment);
751 
752  Time duration = Seconds (0);
753 
754  for (const auto& stations : dlMuAggrTfAcknowledgment->stationsReplyingWithBlockAck)
755  {
756  // compute the TX duration of the BlockAck response from this receiver.
757  const auto& info = stations.second;
758  NS_ASSERT (info.blockAckTxVector.GetHeMuUserInfoMap ().size () == 1);
759  uint16_t staId = info.blockAckTxVector.GetHeMuUserInfoMap ().begin ()->first;
760  Time currBlockAckDuration = m_phy->CalculateTxDuration (GetBlockAckSize (info.baType),
761  info.blockAckTxVector,
762  m_phy->GetPhyBand (),
763  staId);
764  // update the max duration among all the Block Ack responses
765  if (currBlockAckDuration > duration)
766  {
767  duration = currBlockAckDuration;
768  }
769  }
770 
771  // The computed duration may not be coded exactly in the L-SIG length, hence determine
772  // the exact duration corresponding to the value that will be coded in this field.
773  dlMuAggrTfAcknowledgment->ulLength = HePhy::ConvertHeTbPpduDurationToLSigLength (duration, m_phy->GetPhyBand ());
774  WifiTxVector& txVector = dlMuAggrTfAcknowledgment->stationsReplyingWithBlockAck.begin ()->second.blockAckTxVector;
775  duration = HePhy::ConvertLSigLengthToHeTbPpduDuration (dlMuAggrTfAcknowledgment->ulLength,
776  txVector, m_phy->GetPhyBand ());
777 
778  dlMuAggrTfAcknowledgment->acknowledgmentTime = m_phy->GetSifs () + duration;
779  }
780  /*
781  * Basic Trigger Frame starting an UL MU transmission
782  */
783  else if (acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA)
784  {
785  WifiUlMuMultiStaBa* ulMuMultiStaBa = static_cast<WifiUlMuMultiStaBa*> (acknowledgment);
786 
787  Time duration = m_phy->CalculateTxDuration (GetBlockAckSize (ulMuMultiStaBa->baType),
788  ulMuMultiStaBa->multiStaBaTxVector,
789  m_phy->GetPhyBand ());
790  ulMuMultiStaBa->acknowledgmentTime = m_phy->GetSifs () + duration;
791  }
792  /*
793  * TB PPDU solicired by a Basic or BSRP Trigger Frame
794  */
795  else if (acknowledgment->method == WifiAcknowledgment::ACK_AFTER_TB_PPDU)
796  {
797  // The station solicited by the Trigger Frame does not have to account
798  // for the actual acknowledgment time since it is given the PPDU duration
799  // through the Trigger Frame
800  acknowledgment->acknowledgmentTime = Seconds (0);
801  }
802  else
803  {
804  VhtFrameExchangeManager::CalculateAcknowledgmentTime (acknowledgment);
805  }
806 }
807 
808 Time
809 HeFrameExchangeManager::GetTxDuration (uint32_t ppduPayloadSize, Mac48Address receiver,
810  const WifiTxParameters& txParams) const
811 {
812  if (!txParams.m_txVector.IsMu ())
813  {
814  return VhtFrameExchangeManager::GetTxDuration (ppduPayloadSize, receiver, txParams);
815  }
816 
817  NS_ASSERT_MSG (!txParams.m_txVector.IsDlMu () || m_apMac != 0, "DL MU can be done by an AP");
818  NS_ASSERT_MSG (!txParams.m_txVector.IsUlMu () || m_staMac != 0, "UL MU can be done by a STA");
819 
820  if (txParams.m_acknowledgment
821  && txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF)
822  {
823  // we need to account for the size of the aggregated MU-BAR Trigger Frame
824  WifiDlMuAggregateTf* acknowledgment = static_cast<WifiDlMuAggregateTf*> (txParams.m_acknowledgment.get ());
825 
826  const auto& info = acknowledgment->stationsReplyingWithBlockAck.find (receiver);
827  NS_ASSERT (info != acknowledgment->stationsReplyingWithBlockAck.end ());
828 
829  ppduPayloadSize = MpduAggregator::GetSizeIfAggregated (info->second.muBarSize, ppduPayloadSize);
830  }
831 
832  uint16_t staId = (txParams.m_txVector.IsDlMu () ? m_apMac->GetAssociationId (receiver)
833  : m_staMac->GetAssociationId ());
834  Time psduDuration = m_phy->CalculateTxDuration (ppduPayloadSize, txParams.m_txVector,
835  m_phy->GetPhyBand (), staId);
836 
837  return std::max (psduDuration, txParams.m_txDuration);
838 }
839 
840 void
841 HeFrameExchangeManager::TbPpduTimeout (WifiPsduMap* psduMap,
842  const std::set<Mac48Address>* staMissedTbPpduFrom,
843  std::size_t nSolicitedStations)
844 {
845  NS_LOG_FUNCTION (this << psduMap << staMissedTbPpduFrom->size () << nSolicitedStations);
846 
847  NS_ASSERT (psduMap != nullptr);
848  NS_ASSERT (psduMap->size () == 1 && psduMap->begin ()->first == SU_STA_ID
849  && psduMap->begin ()->second->GetHeader (0).IsTrigger ());
850 
851  // This method is called if some station(s) did not send a TB PPDU
852  NS_ASSERT (!staMissedTbPpduFrom->empty ());
853  NS_ASSERT (m_edca != 0);
854 
855  if (staMissedTbPpduFrom->size () == nSolicitedStations)
856  {
857  // no station replied, the transmission failed
858  m_edca->UpdateFailedCw ();
859 
860  TransmissionFailed ();
861  }
862  else if (!m_multiStaBaEvent.IsRunning ())
863  {
864  m_edca->ResetCw ();
865  TransmissionSucceeded ();
866  }
867 
868  m_psduMap.clear ();
869 }
870 
871 void
872 HeFrameExchangeManager::BlockAcksInTbPpduTimeout (WifiPsduMap* psduMap,
873  const std::set<Mac48Address>* staMissedBlockAckFrom,
874  std::size_t nSolicitedStations)
875 {
876  NS_LOG_FUNCTION (this << psduMap << nSolicitedStations);
877 
878  NS_ASSERT (psduMap != nullptr);
879  NS_ASSERT (m_txParams.m_acknowledgment
880  && (m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF
881  || m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_TF_MU_BAR));
882 
883  // This method is called if some station(s) did not send a BlockAck frame in a TB PPDU
884  NS_ASSERT (!staMissedBlockAckFrom->empty ());
885 
886  bool resetCw;
887 
888  if (staMissedBlockAckFrom->size () == nSolicitedStations)
889  {
890  // no station replied, the transmission failed
891  // call ReportDataFailed to increase SRC/LRC
892  m_mac->GetWifiRemoteStationManager ()->ReportDataFailed (*psduMap->begin ()->second->begin ());
893  resetCw = false;
894  }
895  else
896  {
897  // the transmission succeeded
898  resetCw = true;
899  }
900 
901  m_triggerFrame = nullptr; // this is strictly needed for DL_MU_TF_MU_BAR only
902 
903  for (const auto& sta : *staMissedBlockAckFrom)
904  {
905  Ptr<WifiPsdu> psdu = GetPsduTo (sta, *psduMap);
906  NS_ASSERT (psdu != nullptr);
907  // If the QSRC[AC] or the QLRC[AC] has reached dot11ShortRetryLimit or dot11LongRetryLimit
908  // respectively, CW[AC] shall be reset to CWmin[AC] (sec. 10.22.2.2 of 802.11-2016).
909  // We should get that psduResetCw is the same for all PSDUs, but the handling of QSRC/QLRC
910  // needs to be aligned to the specifications.
911  bool psduResetCw;
912  MissedBlockAck (psdu, m_txParams.m_txVector, psduResetCw);
913  resetCw = resetCw || psduResetCw;
914  }
915 
916  NS_ASSERT (m_edca != 0);
917 
918  if (resetCw)
919  {
920  m_edca->ResetCw ();
921  }
922  else
923  {
924  m_edca->UpdateFailedCw ();
925  }
926 
927  if (staMissedBlockAckFrom->size () == nSolicitedStations)
928  {
929  // no station replied, the transmission failed
930  TransmissionFailed ();
931  }
932  else
933  {
934  TransmissionSucceeded ();
935  }
936  m_psduMap.clear ();
937 }
938 
939 void
940 HeFrameExchangeManager::BlockAckAfterTbPpduTimeout (Ptr<WifiPsdu> psdu, const WifiTxVector& txVector)
941 {
942  NS_LOG_FUNCTION (this << *psdu << txVector);
943 
944  bool resetCw;
945 
946  // call ReportDataFailed to increase SRC/LRC
947  m_mac->GetWifiRemoteStationManager ()->ReportDataFailed (*psdu->begin ());
948 
949  MissedBlockAck (psdu, m_txParams.m_txVector, resetCw);
950 
951  // This is a PSDU sent in a TB PPDU. An HE STA resumes the EDCA backoff procedure
952  // without modifying CW or the backoff counter for the associated EDCAF, after
953  // transmission of an MPDU in a TB PPDU regardless of whether the STA has received
954  // the corresponding acknowledgment frame in response to the MPDU sent in the TB PPDU
955  // (Sec. 10.22.2.2 of 11ax Draft 3.0)
956  m_psduMap.clear ();
957 }
958 
960 HeFrameExchangeManager::GetHeTbTxVector (CtrlTriggerHeader trigger, Mac48Address triggerSender) const
961 {
962  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)
963  NS_ASSERT (m_staMac != nullptr);
964  uint16_t staId = m_staMac->GetAssociationId ();
965  auto userInfoIt = trigger.FindUserInfoWithAid (staId);
966  NS_ASSERT (userInfoIt != trigger.end ());
967 
968  WifiTxVector v = trigger.GetHeTbTxVector (staId);
969 
970  Ptr<HeConfiguration> heConfiguration = m_mac->GetHeConfiguration ();
971  NS_ASSERT_MSG (heConfiguration != 0, "This STA has to be an HE station to send an HE TB PPDU");
972  v.SetBssColor (heConfiguration->GetBssColor ());
973 
974  uint8_t powerLevel = m_mac->GetWifiRemoteStationManager ()->GetDefaultTxPowerLevel ();
992  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
993  double reqTxPowerDbm = static_cast<double> (userInfoIt->GetUlTargetRssi () + pathLossDb);
994 
995  //Convert the transmit power to a power level
996  uint8_t numPowerLevels = m_phy->GetNTxPower ();
997  if (numPowerLevels > 1)
998  {
999  double stepDbm = (m_phy->GetTxPowerEnd () - m_phy->GetTxPowerStart ()) / (numPowerLevels - 1);
1000  powerLevel = static_cast<uint8_t> (ceil ((reqTxPowerDbm - m_phy->GetTxPowerStart ()) / stepDbm)); //better be slightly above so as to satisfy target UL RSSI
1001  if (powerLevel > numPowerLevels)
1002  {
1003  powerLevel = numPowerLevels; //capping will trigger warning below
1004  }
1005  }
1006  if (reqTxPowerDbm > m_phy->GetPowerDbm (powerLevel))
1007  {
1008  NS_LOG_WARN ("The requested power level (" << reqTxPowerDbm << "dBm) cannot be satisfied (max: " << m_phy->GetTxPowerEnd () << "dBm)");
1009  }
1010  v.SetTxPowerLevel (powerLevel);
1011  NS_LOG_LOGIC ("UL power control: "
1012  << "input {pathLoss=" << pathLossDb << "dB, reqTxPower=" << reqTxPowerDbm << "dBm}"
1013  << " output {powerLevel=" << +powerLevel << " -> " << m_phy->GetPowerDbm (powerLevel) << "dBm}"
1014  << " PHY power capa {min=" << m_phy->GetTxPowerStart () << "dBm, max=" << m_phy->GetTxPowerEnd () << "dBm, levels:" << +numPowerLevels << "}");
1015 
1016  return v;
1017 }
1018 
1019 void
1020 HeFrameExchangeManager::SetTargetRssi (CtrlTriggerHeader& trigger) const
1021 {
1022  NS_LOG_FUNCTION (this);
1023  NS_ASSERT (m_apMac != 0);
1024 
1025  trigger.SetApTxPower (static_cast<int8_t> (m_phy->GetPowerDbm (m_mac->GetWifiRemoteStationManager ()->GetDefaultTxPowerLevel ())));
1026  for (auto& userInfo : trigger)
1027  {
1028  const auto staList = m_apMac->GetStaList ();
1029  auto itAidAddr = staList.find (userInfo.GetAid12 ());
1030  NS_ASSERT (itAidAddr != staList.end ());
1031  int8_t rssi = static_cast<int8_t> (m_mac->GetWifiRemoteStationManager ()->GetMostRecentRssi (itAidAddr->second));
1032  rssi = (rssi >= -20) ? -20 : ((rssi <= -110) ? -110 : rssi); //cap so as to keep within [-110; -20] dBm
1033  userInfo.SetUlTargetRssi (rssi);
1034  }
1035 }
1036 
1037 void
1038 HeFrameExchangeManager::SendMultiStaBlockAck (const WifiTxParameters& txParams)
1039 {
1040  NS_LOG_FUNCTION (this << &txParams);
1041 
1042  NS_ASSERT (m_apMac != 0);
1043  NS_ASSERT (txParams.m_acknowledgment
1044  && txParams.m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
1045  WifiUlMuMultiStaBa* acknowledgment = static_cast<WifiUlMuMultiStaBa*> (txParams.m_acknowledgment.get ());
1046 
1047  NS_ASSERT (!acknowledgment->stationsReceivingMultiStaBa.empty ());
1048 
1049  CtrlBAckResponseHeader blockAck;
1050  blockAck.SetType (acknowledgment->baType);
1051 
1052  Mac48Address receiver;
1053 
1054  for (const auto& staInfo : acknowledgment->stationsReceivingMultiStaBa)
1055  {
1056  receiver = staInfo.first.first;
1057  uint8_t tid = staInfo.first.second;
1058  std::size_t index = staInfo.second;
1059 
1060  blockAck.SetAid11 (m_apMac->GetAssociationId (receiver), index);
1061  blockAck.SetTidInfo (tid, index);
1062 
1063  if (tid == 14)
1064  {
1065  // All-ack context
1066  NS_LOG_DEBUG ("Multi-STA Block Ack: Sending All-ack to=" << receiver);
1067  blockAck.SetAckType (true, index);
1068  continue;
1069  }
1070 
1071  if (acknowledgment->baType.m_bitmapLen.at (index) == 0)
1072  {
1073  // Acknowledgment context
1074  NS_LOG_DEBUG ("Multi-STA Block Ack: Sending Ack to=" << receiver);
1075  blockAck.SetAckType (true, index);
1076  }
1077  else
1078  {
1079  // Block acknowledgment context
1080  blockAck.SetAckType (false, index);
1081 
1082  auto addressTidPair = staInfo.first;
1083  auto agreementIt = m_agreements.find (addressTidPair);
1084  NS_ASSERT (agreementIt != m_agreements.end ());
1085  agreementIt->second.FillBlockAckBitmap (&blockAck, index);
1086  NS_LOG_DEBUG ("Multi-STA Block Ack: Sending Block Ack with seq=" << blockAck.GetStartingSequence (index)
1087  << " to=" << receiver << " tid=" << +tid);
1088  }
1089  }
1090 
1091  WifiMacHeader hdr;
1093  hdr.SetAddr1 (acknowledgment->stationsReceivingMultiStaBa.size () == 1 ? receiver : Mac48Address::GetBroadcast ());
1094  hdr.SetAddr2 (m_self);
1095  hdr.SetDsNotFrom ();
1096  hdr.SetDsNotTo ();
1097 
1098  Ptr<Packet> packet = Create<Packet> ();
1099  packet->AddHeader (blockAck);
1100  Ptr<WifiPsdu> psdu = GetWifiPsdu (Create<WifiMacQueueItem> (packet, hdr),
1101  acknowledgment->multiStaBaTxVector);
1102 
1103  // The Duration/ID field in a BlockAck frame transmitted in response to a frame
1104  // carried in HE TB PPDU is set according to the multiple protection settings
1105  // (Sec. 9.2.5.7 of 802.11ax D3.0)
1106  Time txDuration = m_phy->CalculateTxDuration (GetBlockAckSize (acknowledgment->baType),
1107  acknowledgment->multiStaBaTxVector,
1108  m_phy->GetPhyBand ());
1109  WifiTxParameters params;
1110  // if the TXOP limit is null, GetPsduDurationId returns the acknowledgment time,
1111  // hence we set an method with acknowledgment time equal to zero.
1112  params.m_acknowledgment = std::unique_ptr<WifiAcknowledgment> (new WifiNoAck);
1113  psdu->SetDuration (GetPsduDurationId (txDuration, params));
1114 
1115  psdu->GetPayload (0)->AddPacketTag (m_muSnrTag);
1116 
1117  ForwardPsduDown (psdu, acknowledgment->multiStaBaTxVector);
1118 
1119  // continue with the TXOP if time remains
1120  m_psduMap.clear ();
1121  m_edca->ResetCw ();
1122  m_muSnrTag.Reset ();
1123  Simulator::Schedule (txDuration, &HeFrameExchangeManager::TransmissionSucceeded, this);
1124 }
1125 
1126 void
1127 HeFrameExchangeManager::ReceiveBasicTrigger (const CtrlTriggerHeader& trigger, const WifiMacHeader& hdr)
1128 {
1129  NS_LOG_FUNCTION (this << trigger << hdr);
1130  NS_ASSERT (trigger.IsBasic ());
1131  NS_ASSERT (m_staMac != 0 && m_staMac->IsAssociated ());
1132 
1133  NS_LOG_DEBUG ("Received a Trigger Frame (basic variant) soliciting a transmission");
1134 
1135  if (trigger.GetCsRequired () && hdr.GetAddr2 () != m_txopHolder && m_navEnd > Simulator::Now ())
1136  {
1137  NS_LOG_DEBUG ("Carrier Sensing required and channel busy, do nothing");
1138  return;
1139  }
1140 
1141  // Starting from the Preferred AC indicated in the Trigger Frame, check if there
1142  // is either a pending BlockAckReq frame or a data frame that can be transmitted
1143  // in the allocated time and is addressed to a station with which a Block Ack
1144  // agreement has been established.
1145 
1146  // create the sequence of TIDs to check
1147  std::vector<uint8_t> tids;
1148  uint16_t staId = m_staMac->GetAssociationId ();
1149  AcIndex preferredAc = trigger.FindUserInfoWithAid (staId)->GetPreferredAc ();
1150  auto acIt = wifiAcList.find (preferredAc);
1151  for (uint8_t i = 0; i < 4; i++)
1152  {
1153  NS_ASSERT (acIt != wifiAcList.end ());
1154  tids.push_back (acIt->second.GetHighTid ());
1155  tids.push_back (acIt->second.GetLowTid ());
1156 
1157  acIt++;
1158  if (acIt == wifiAcList.end ())
1159  {
1160  acIt = wifiAcList.begin ();
1161  }
1162  }
1163 
1165  Ptr<WifiPsdu> psdu;
1166  WifiTxParameters txParams;
1167  WifiTxVector tbTxVector = GetHeTbTxVector (trigger, hdr.GetAddr2 ());
1168  Time ppduDuration = HePhy::ConvertLSigLengthToHeTbPpduDuration (trigger.GetUlLength (),
1169  tbTxVector,
1170  m_phy->GetPhyBand ());
1171 
1172  for (const auto& tid : tids)
1173  {
1174  Ptr<QosTxop> edca = m_mac->GetQosTxop (tid);
1175 
1176  if (!edca->GetBaAgreementEstablished (hdr.GetAddr2 (), tid))
1177  {
1178  // no Block Ack agreement established for this TID
1179  continue;
1180  }
1181 
1182  txParams.Clear ();
1183  txParams.m_txVector = tbTxVector;
1184 
1185  // first, check if there is a pending BlockAckReq frame
1186  if ((mpdu = edca->GetBaManager ()->GetBar (false, tid, hdr.GetAddr2 ())) != 0
1187  && TryAddMpdu (mpdu, txParams, ppduDuration))
1188  {
1189  NS_LOG_DEBUG ("Sending a BAR within a TB PPDU");
1190  psdu = Create<WifiPsdu> (edca->GetBaManager ()->GetBar (true, tid, hdr.GetAddr2 ()), true);
1191  break;
1192  }
1193 
1194  // otherwise, check if a suitable data frame is available
1195  if ((mpdu = edca->PeekNextMpdu (tid, hdr.GetAddr2 ())) != 0)
1196  {
1198  Ptr<WifiMacQueueItem> item = edca->GetNextMpdu (mpdu, txParams, ppduDuration, false, queueIt);
1199 
1200  if (item != 0)
1201  {
1202  // try A-MPDU aggregation
1203  std::vector<Ptr<WifiMacQueueItem>> mpduList = m_mpduAggregator->GetNextAmpdu (item, txParams,
1204  ppduDuration,
1205  queueIt);
1206  psdu = (mpduList.size () > 1 ? Create<WifiPsdu> (std::move (mpduList))
1207  : Create<WifiPsdu> (item, true));
1208  break;
1209  }
1210  }
1211  }
1212 
1213  if (psdu != 0)
1214  {
1215  psdu->SetDuration (hdr.GetDuration () - m_phy->GetSifs () - ppduDuration);
1216  SendPsduMapWithProtection (WifiPsduMap {{staId, psdu}}, txParams);
1217  }
1218  else
1219  {
1220  // send QoS Null frames
1221  SendQosNullFramesInTbPpdu (trigger, hdr);
1222  }
1223 }
1224 
1225 void
1226 HeFrameExchangeManager::SendQosNullFramesInTbPpdu (const CtrlTriggerHeader& trigger, const WifiMacHeader& hdr)
1227 {
1228  NS_LOG_FUNCTION (this << trigger << hdr);
1229  NS_ASSERT (trigger.IsBasic () || trigger.IsBsrp ());
1230  NS_ASSERT (m_staMac != 0 && m_staMac->IsAssociated ());
1231 
1232  NS_LOG_DEBUG ("Requested to send QoS Null frames");
1233 
1234  if (trigger.GetCsRequired () && hdr.GetAddr2 () != m_txopHolder && m_navEnd > Simulator::Now ())
1235  {
1236  NS_LOG_DEBUG ("Carrier Sensing required and channel busy, do nothing");
1237  return;
1238  }
1239 
1240  WifiMacHeader header;
1241  header.SetType (WIFI_MAC_QOSDATA_NULL);
1242  header.SetAddr1 (hdr.GetAddr2 ());
1243  header.SetAddr2 (m_self);
1244  header.SetAddr3 (hdr.GetAddr2 ());
1245  header.SetDsTo ();
1246  header.SetDsNotFrom ();
1247  // TR3: Sequence numbers for transmitted QoS (+)Null frames may be set
1248  // to any value. (Table 10-3 of 802.11-2016)
1249  header.SetSequenceNumber (0);
1250  // Set the EOSP bit so that NotifyTxToEdca will add the Queue Size
1251  header.SetQosEosp ();
1252 
1253  WifiTxParameters txParams;
1254  txParams.m_txVector = GetHeTbTxVector (trigger, hdr.GetAddr2 ());
1255  txParams.m_protection = std::unique_ptr<WifiProtection> (new WifiNoProtection);
1256  txParams.m_acknowledgment = std::unique_ptr<WifiAcknowledgment> (new WifiNoAck);
1257 
1258  Time ppduDuration = HePhy::ConvertLSigLengthToHeTbPpduDuration (trigger.GetUlLength (),
1259  txParams.m_txVector,
1260  m_phy->GetPhyBand ());
1261  header.SetDuration (hdr.GetDuration () - m_phy->GetSifs () - ppduDuration);
1262 
1263  Ptr<WifiMacQueueItem> mpdu;
1264  std::vector<Ptr<WifiMacQueueItem>> mpduList;
1265  uint8_t tid = 0;
1266  header.SetQosTid (tid);
1267 
1268  while (tid < 8
1269  && IsWithinSizeAndTimeLimits (txParams.GetSizeIfAddMpdu (mpdu = Create<WifiMacQueueItem> (Create<Packet> (),
1270  header)),
1271  hdr.GetAddr2 (), txParams, ppduDuration))
1272  {
1273  NS_LOG_DEBUG ("Aggregating a QoS Null frame with tid=" << +tid);
1274  // We could call TryAddMpdu instead of IsWithinSizeAndTimeLimits above in order to
1275  // get the TX parameters updated automatically. However, aggregating the QoS Null
1276  // frames might fail because MPDU aggregation is disabled by default for VO
1277  // and BK. Therefore, we skip the check on max A-MPDU size and only update the
1278  // TX parameters below.
1279  txParams.m_acknowledgment = GetAckManager ()->TryAddMpdu (mpdu, txParams);
1280  txParams.AddMpdu (mpdu);
1281  UpdateTxDuration (mpdu->GetHeader ().GetAddr1 (), txParams);
1282  mpduList.push_back (mpdu);
1283  header.SetQosTid (++tid);
1284  }
1285 
1286  if (mpduList.empty ())
1287  {
1288  NS_LOG_DEBUG ("Not enough time to send a QoS Null frame");
1289  return;
1290  }
1291 
1292  Ptr<WifiPsdu> psdu = (mpduList.size () > 1 ? Create<WifiPsdu> (std::move (mpduList))
1293  : Create<WifiPsdu> (mpduList.front (), true));
1294  uint16_t staId = m_staMac->GetAssociationId ();
1295  SendPsduMapWithProtection (WifiPsduMap {{staId, psdu}}, txParams);
1296 }
1297 
1298 void
1299 HeFrameExchangeManager::ReceiveMpdu (Ptr<WifiMacQueueItem> mpdu, RxSignalInfo rxSignalInfo,
1300  const WifiTxVector& txVector, bool inAmpdu)
1301 {
1302  // The received MPDU is either broadcast or addressed to this station
1303  NS_ASSERT (mpdu->GetHeader ().GetAddr1 ().IsBroadcast ()
1304  || mpdu->GetHeader ().GetAddr1 () == m_self);
1305 
1306  const WifiMacHeader& hdr = mpdu->GetHeader ();
1307 
1308  if (txVector.IsUlMu () && m_txTimer.IsRunning ()
1309  && m_txTimer.GetReason () == WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF)
1310  {
1311  Mac48Address sender = hdr.GetAddr2 ();
1312  NS_ASSERT (m_txParams.m_acknowledgment
1313  && m_txParams.m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
1314  WifiUlMuMultiStaBa* acknowledgment = static_cast<WifiUlMuMultiStaBa*> (m_txParams.m_acknowledgment.get ());
1315  std::size_t index = acknowledgment->baType.m_bitmapLen.size ();
1316 
1317  if (m_staExpectTbPpduFrom.find (sender) == m_staExpectTbPpduFrom.end ())
1318  {
1319  NS_LOG_WARN ("Received a TB PPDU from an unexpected station: " << sender);
1320  return;
1321  }
1322 
1323  if (hdr.IsBlockAckReq ())
1324  {
1325  NS_LOG_DEBUG ("Received a BlockAckReq in a TB PPDU from " << sender);
1326 
1327  CtrlBAckRequestHeader blockAckReq;
1328  mpdu->GetPacket ()->PeekHeader (blockAckReq);
1329  NS_ABORT_MSG_IF (blockAckReq.IsMultiTid (), "Multi-TID BlockAckReq not supported");
1330  uint8_t tid = blockAckReq.GetTidInfo ();
1331  auto agreementIt = m_agreements.find ({sender, tid});
1332  NS_ASSERT (agreementIt != m_agreements.end ());
1333  agreementIt->second.NotifyReceivedBar (blockAckReq.GetStartingSequence ());
1334 
1335  // Block Acknowledgment context
1336  acknowledgment->stationsReceivingMultiStaBa.emplace (std::make_pair (sender, tid), index);
1337  acknowledgment->baType.m_bitmapLen.push_back (GetBlockAckType (sender, tid).m_bitmapLen.at (0));
1338  uint16_t staId = txVector.GetHeMuUserInfoMap ().begin ()->first;
1339  m_muSnrTag.Set (staId, rxSignalInfo.snr);
1340  }
1341  else if (hdr.IsQosData () && !inAmpdu && hdr.GetQosAckPolicy () == WifiMacHeader::NORMAL_ACK)
1342  {
1343  NS_LOG_DEBUG ("Received an S-MPDU in a TB PPDU from " << sender << " (" << *mpdu << ")");
1344 
1345  uint8_t tid = hdr.GetQosTid ();
1346  auto agreementIt = m_agreements.find ({sender, tid});
1347  NS_ASSERT (agreementIt != m_agreements.end ());
1348  agreementIt->second.NotifyReceivedMpdu (mpdu);
1349 
1350  // Acknowledgment context of Multi-STA Block Acks
1351  acknowledgment->stationsReceivingMultiStaBa.emplace (std::make_pair (sender, tid), index);
1352  acknowledgment->baType.m_bitmapLen.push_back (0);
1353  uint16_t staId = txVector.GetHeMuUserInfoMap ().begin ()->first;
1354  m_muSnrTag.Set (staId, rxSignalInfo.snr);
1355  }
1356  else if (!(hdr.IsQosData () && !hdr.HasData () && !inAmpdu))
1357  {
1358  // The other case handled by this function is when we receive a QoS Null frame
1359  // that is not in an A-MPDU. For all other cases, the reception is handled by
1360  // parent classes. In particular, in case of a QoS data frame in A-MPDU, we
1361  // have to wait until the A-MPDU reception is completed, but we let the
1362  // parent classes notify the Block Ack agreement of the reception of this MPDU
1363  VhtFrameExchangeManager::ReceiveMpdu (mpdu, rxSignalInfo, txVector, inAmpdu);
1364  return;
1365  }
1366 
1367  // Schedule the transmission of a Multi-STA BlockAck frame if needed
1368  if (!acknowledgment->stationsReceivingMultiStaBa.empty () && !m_multiStaBaEvent.IsRunning ())
1369  {
1370  m_multiStaBaEvent = Simulator::Schedule (m_phy->GetSifs (),
1371  &HeFrameExchangeManager::SendMultiStaBlockAck,
1372  this, std::cref (m_txParams));
1373  }
1374 
1375  // remove the sender from the set of stations that are expected to send a TB PPDU
1376  m_staExpectTbPpduFrom.erase (sender);
1377 
1378  if (m_staExpectTbPpduFrom.empty ())
1379  {
1380  // we do not expect any other BlockAck frame
1381  m_txTimer.Cancel ();
1382  m_channelAccessManager->NotifyAckTimeoutResetNow ();
1383 
1384  if (!m_multiStaBaEvent.IsRunning ())
1385  {
1386  // all of the stations that replied with a TB PPDU sent QoS Null frames.
1387  NS_LOG_DEBUG ("Continue the TXOP");
1388  m_psduMap.clear ();
1389  m_edca->ResetCw ();
1390  TransmissionSucceeded ();
1391  }
1392  }
1393 
1394  // the received TB PPDU has been processed
1395  return;
1396  }
1397 
1398  if (hdr.IsCtl ())
1399  {
1400  if (hdr.IsAck () && m_txTimer.IsRunning ()
1401  && m_txTimer.GetReason () == WifiTxTimer::WAIT_NORMAL_ACK_AFTER_DL_MU_PPDU)
1402  {
1403  NS_ASSERT (hdr.GetAddr1 () == m_self);
1404  NS_ASSERT (m_txParams.m_acknowledgment);
1405  NS_ASSERT (m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE);
1406 
1407  WifiDlMuBarBaSequence* acknowledgment = static_cast<WifiDlMuBarBaSequence*> (m_txParams.m_acknowledgment.get ());
1408  NS_ASSERT (acknowledgment->stationsReplyingWithNormalAck.size () == 1);
1409  NS_ASSERT (m_apMac != 0);
1410  uint16_t staId = m_apMac->GetAssociationId (acknowledgment->stationsReplyingWithNormalAck.begin ()->first);
1411  auto it = m_psduMap.find (staId);
1412  NS_ASSERT (it != m_psduMap.end ());
1413  NS_ASSERT (it->second->GetAddr1 () == acknowledgment->stationsReplyingWithNormalAck.begin ()->first);
1414  SnrTag tag;
1415  mpdu->GetPacket ()->PeekPacketTag (tag);
1416  ReceivedNormalAck (*it->second->begin (), m_txParams.m_txVector, txVector, rxSignalInfo, tag.Get ());
1417  }
1418  else if (hdr.IsBlockAck () && m_txTimer.IsRunning ()
1419  && m_txTimer.GetReason () == WifiTxTimer::WAIT_BLOCK_ACKS_IN_TB_PPDU)
1420  {
1421  Mac48Address sender = hdr.GetAddr2 ();
1422  NS_LOG_DEBUG ("Received BlockAck in TB PPDU from=" << sender);
1423 
1424  SnrTag tag;
1425  mpdu->GetPacket ()->PeekPacketTag (tag);
1426 
1427  // notify the Block Ack Manager
1428  CtrlBAckResponseHeader blockAck;
1429  mpdu->GetPacket ()->PeekHeader (blockAck);
1430  uint8_t tid = blockAck.GetTidInfo ();
1431  std::pair<uint16_t,uint16_t> ret = GetBaManager (tid)->NotifyGotBlockAck (blockAck, hdr.GetAddr2 (),
1432  {tid});
1433  m_mac->GetWifiRemoteStationManager ()->ReportAmpduTxStatus (hdr.GetAddr2 (), ret.first, ret.second,
1434  rxSignalInfo.snr, tag.Get (), m_txParams.m_txVector);
1435 
1436  // remove the sender from the set of stations that are expected to send a BlockAck
1437  if (m_staExpectTbPpduFrom.erase (sender) == 0)
1438  {
1439  NS_LOG_WARN ("Received a BlockAck from an unexpected stations: " << sender);
1440  return;
1441  }
1442 
1443  if (m_staExpectTbPpduFrom.empty ())
1444  {
1445  // we do not expect any other BlockAck frame
1446  m_txTimer.Cancel ();
1447  m_channelAccessManager->NotifyAckTimeoutResetNow ();
1448  m_triggerFrame = nullptr; // this is strictly needed for DL_MU_TF_MU_BAR only
1449 
1450  m_edca->ResetCw ();
1451  m_psduMap.clear ();
1452  TransmissionSucceeded ();
1453  }
1454  }
1455  else if (hdr.IsBlockAck () && m_txTimer.IsRunning ()
1456  && m_txTimer.GetReason () == WifiTxTimer::WAIT_BLOCK_ACK_AFTER_TB_PPDU)
1457  {
1458  CtrlBAckResponseHeader blockAck;
1459  mpdu->GetPacket ()->PeekHeader (blockAck);
1460 
1461  NS_ABORT_MSG_IF (!blockAck.IsMultiSta (),
1462  "A Multi-STA BlockAck is expected after a TB PPDU");
1463  NS_LOG_DEBUG ("Received a Multi-STA BlockAck from=" << hdr.GetAddr2 ());
1464 
1465  NS_ASSERT (m_staMac != nullptr && m_staMac->IsAssociated ());
1466  uint16_t staId = m_staMac->GetAssociationId ();
1467  std::vector<uint32_t> indices = blockAck.FindPerAidTidInfoWithAid (staId);
1468 
1469  if (indices.empty ())
1470  {
1471  NS_LOG_DEBUG ("No Per AID TID Info subfield intended for me");
1472  return;
1473  }
1474 
1475  MuSnrTag tag;
1476  mpdu->GetPacket ()->PeekPacketTag (tag);
1477 
1478  // notify the Block Ack Manager
1479  for (const auto& index : indices)
1480  {
1481  uint8_t tid = blockAck.GetTidInfo (index);
1482 
1483  if (blockAck.GetAckType (index) && tid < 8)
1484  {
1485  // Acknowledgment context
1486  NS_ABORT_IF (m_psduMap.empty () || m_psduMap.begin ()->first != staId);
1487  GetBaManager (tid)->NotifyGotAck (*m_psduMap.at (staId)->begin ());
1488  }
1489  else
1490  {
1491  // Block Acknowledgment or All-ack context
1492  if (blockAck.GetAckType (index) && tid == 14)
1493  {
1494  // All-ack context, we need to determine the actual TID(s) of the PSDU
1495  NS_ASSERT (indices.size () == 1);
1496  NS_ABORT_IF (m_psduMap.empty () || m_psduMap.begin ()->first != staId);
1497  std::set<uint8_t> tids = m_psduMap.at (staId)->GetTids ();
1498  NS_ABORT_MSG_IF (tids.size () > 1, "Multi-TID A-MPDUs not supported yet");
1499  tid = *tids.begin ();
1500  }
1501 
1502  std::pair<uint16_t,uint16_t> ret = GetBaManager (tid)->NotifyGotBlockAck (blockAck,
1503  hdr.GetAddr2 (),
1504  {tid}, index);
1505  m_mac->GetWifiRemoteStationManager ()->ReportAmpduTxStatus (hdr.GetAddr2 (), ret.first,
1506  ret.second, rxSignalInfo.snr,
1507  tag.Get (staId), m_txParams.m_txVector);
1508  }
1509 
1510  if (m_psduMap.at (staId)->GetHeader (0).IsQosData ()
1511  && (blockAck.GetAckType (index) // Ack or All-ack context
1512  || std::any_of (blockAck.GetBitmap (index).begin (),
1513  blockAck.GetBitmap (index).end (),
1514  [](uint8_t b) { return b != 0; })))
1515  {
1516  NS_ASSERT (m_psduMap.at (staId)->GetHeader (0).HasData ());
1517  NS_ASSERT (m_psduMap.at (staId)->GetHeader (0).GetQosTid () == tid);
1518  // the station has received a response from the AP for the HE TB PPDU
1519  // transmitted in response to a Basic Trigger Frame and at least one
1520  // MPDU was acknowledged. Therefore, it needs to update the access
1521  // parameters if it received an MU EDCA Parameter Set element.
1522  m_mac->GetQosTxop (tid)->StartMuEdcaTimerNow ();
1523  }
1524  }
1525 
1526  // cancel the timer
1527  m_txTimer.Cancel ();
1528  m_channelAccessManager->NotifyAckTimeoutResetNow ();
1529  m_psduMap.clear ();
1530  }
1531  else if (hdr.IsTrigger ())
1532  {
1533  // Trigger Frames are only processed by STAs
1534  if (m_staMac == nullptr)
1535  {
1536  return;
1537  }
1538 
1539  // A Trigger Frame in an A-MPDU is processed when the A-MPDU is fully received
1540  if (inAmpdu)
1541  {
1542  m_triggerFrameInAmpdu = true;
1543  return;
1544  }
1545 
1546  CtrlTriggerHeader trigger;
1547  mpdu->GetPacket ()->PeekHeader (trigger);
1548 
1549  if (hdr.GetAddr1 () != m_self
1550  && (!hdr.GetAddr1 ().IsBroadcast ()
1551  || !m_staMac->IsAssociated ()
1552  || hdr.GetAddr2 () != m_bssid // not sent by the AP this STA is associated with
1553  || trigger.FindUserInfoWithAid (m_staMac->GetAssociationId ()) == trigger.end ()))
1554  {
1555  // not addressed to us
1556  return;
1557  }
1558 
1559  uint16_t staId = m_staMac->GetAssociationId ();
1560 
1561  if (trigger.IsMuBar ())
1562  {
1563  Mac48Address sender = hdr.GetAddr2 ();
1564  NS_LOG_DEBUG ("Received MU-BAR Trigger Frame from=" << sender);
1565  m_mac->GetWifiRemoteStationManager ()->ReportRxOk (sender, rxSignalInfo, txVector);
1566 
1567  auto userInfoIt = trigger.FindUserInfoWithAid (staId);
1568  NS_ASSERT (userInfoIt != trigger.end ());
1569  CtrlBAckRequestHeader blockAckReq = userInfoIt->GetMuBarTriggerDepUserInfo ();
1570  NS_ABORT_MSG_IF (blockAckReq.IsMultiTid (), "Multi-TID BlockAckReq not supported");
1571  uint8_t tid = blockAckReq.GetTidInfo ();
1572 
1573  auto agreementIt = m_agreements.find ({sender, tid});
1574 
1575  if (agreementIt == m_agreements.end ())
1576  {
1577  NS_LOG_DEBUG ("There's not a valid agreement for this BlockAckReq");
1578  return;
1579  }
1580 
1581  agreementIt->second.NotifyReceivedBar (blockAckReq.GetStartingSequence ());
1582 
1583  NS_LOG_DEBUG ("Schedule Block Ack in TB PPDU");
1584  Simulator::Schedule (m_phy->GetSifs (), &HeFrameExchangeManager::SendBlockAck, this,
1585  agreementIt->second, hdr.GetDuration (),
1586  GetHeTbTxVector (trigger, hdr.GetAddr2 ()), rxSignalInfo.snr);
1587  }
1588  else if (trigger.IsBasic ())
1589  {
1590  Simulator::Schedule (m_phy->GetSifs (), &HeFrameExchangeManager::ReceiveBasicTrigger,
1591  this, trigger, hdr);
1592  }
1593  else if (trigger.IsBsrp ())
1594  {
1595  Simulator::Schedule (m_phy->GetSifs (), &HeFrameExchangeManager::SendQosNullFramesInTbPpdu,
1596  this, trigger, hdr);
1597  }
1598  }
1599  else
1600  {
1601  // the received control frame cannot be handled here
1602  VhtFrameExchangeManager::ReceiveMpdu (mpdu, rxSignalInfo, txVector, inAmpdu);
1603  }
1604 
1605  // the received control frame has been processed
1606  return;
1607  }
1608 
1609  // the received frame cannot be handled here
1610  VhtFrameExchangeManager::ReceiveMpdu (mpdu, rxSignalInfo, txVector, inAmpdu);;
1611 }
1612 
1613 void
1614 HeFrameExchangeManager::EndReceiveAmpdu (Ptr<const WifiPsdu> psdu, const RxSignalInfo& rxSignalInfo,
1615  const WifiTxVector& txVector, const std::vector<bool>& perMpduStatus)
1616 {
1617  std::set<uint8_t> tids = psdu->GetTids ();
1618 
1619  if (txVector.IsUlMu () && m_txTimer.IsRunning ()
1620  && m_txTimer.GetReason () == WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF)
1621  {
1622  Mac48Address sender = psdu->GetAddr2 ();
1623  NS_ASSERT (m_txParams.m_acknowledgment
1624  && m_txParams.m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
1625  WifiUlMuMultiStaBa* acknowledgment = static_cast<WifiUlMuMultiStaBa*> (m_txParams.m_acknowledgment.get ());
1626  std::size_t index = acknowledgment->baType.m_bitmapLen.size ();
1627 
1628  if (m_staExpectTbPpduFrom.find (sender) == m_staExpectTbPpduFrom.end ())
1629  {
1630  NS_LOG_WARN ("Received a TB PPDU from an unexpected station: " << sender);
1631  return;
1632  }
1633 
1634  NS_LOG_DEBUG ("Received an A-MPDU in a TB PPDU from " << sender << " (" << *psdu << ")");
1635 
1636  if (std::any_of (tids.begin (), tids.end (),
1637  [&psdu](uint8_t tid)
1638  { return psdu->GetAckPolicyForTid (tid) == WifiMacHeader::NORMAL_ACK; }))
1639  {
1640  if (std::all_of (perMpduStatus.cbegin (), perMpduStatus.cend (), [](bool v) { return v; }))
1641  {
1642  // All-ack context
1643  acknowledgment->stationsReceivingMultiStaBa.emplace (std::make_pair (sender, 14), index);
1644  acknowledgment->baType.m_bitmapLen.push_back (0);
1645  }
1646  else
1647  {
1648  // Block Acknowledgment context
1649  std::size_t i = 0;
1650  for (const auto& tid : tids)
1651  {
1652  acknowledgment->stationsReceivingMultiStaBa.emplace (std::make_pair (sender, tid), index + i++);
1653  acknowledgment->baType.m_bitmapLen.push_back (GetBlockAckType (sender, tid).m_bitmapLen.at (0));
1654  }
1655  }
1656  uint16_t staId = txVector.GetHeMuUserInfoMap ().begin ()->first;
1657  m_muSnrTag.Set (staId, rxSignalInfo.snr);
1658  }
1659 
1660  // Schedule the transmission of a Multi-STA BlockAck frame if needed
1661  if (!acknowledgment->stationsReceivingMultiStaBa.empty () && !m_multiStaBaEvent.IsRunning ())
1662  {
1663  m_multiStaBaEvent = Simulator::Schedule (m_phy->GetSifs (),
1664  &HeFrameExchangeManager::SendMultiStaBlockAck,
1665  this, std::cref (m_txParams));
1666  }
1667 
1668  // remove the sender from the set of stations that are expected to send a TB PPDU
1669  m_staExpectTbPpduFrom.erase (sender);
1670 
1671  if (m_staExpectTbPpduFrom.empty ())
1672  {
1673  // we do not expect any other BlockAck frame
1674  m_txTimer.Cancel ();
1675  m_channelAccessManager->NotifyAckTimeoutResetNow ();
1676 
1677  if (!m_multiStaBaEvent.IsRunning ())
1678  {
1679  // all of the stations that replied with a TB PPDU sent QoS Null frames.
1680  NS_LOG_DEBUG ("Continue the TXOP");
1681  m_psduMap.clear ();
1682  m_edca->ResetCw ();
1683  TransmissionSucceeded ();
1684  }
1685  }
1686 
1687  // the received TB PPDU has been processed
1688  return;
1689  }
1690 
1691  if (txVector.IsUlMu () && m_txTimer.IsRunning ()
1692  && m_txTimer.GetReason () == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF)
1693  {
1694  Mac48Address sender = psdu->GetAddr2 ();
1695 
1696  if (m_staExpectTbPpduFrom.find (sender) == m_staExpectTbPpduFrom.end ())
1697  {
1698  NS_LOG_WARN ("Received a TB PPDU from an unexpected station: " << sender);
1699  return;
1700  }
1701  if (std::none_of (psdu->begin (), psdu->end (), [](Ptr<WifiMacQueueItem> mpdu)
1702  { return mpdu->GetHeader ().IsQosData ()
1703  && !mpdu->GetHeader ().HasData ();
1704  }))
1705  {
1706  NS_LOG_WARN ("No QoS Null frame in the received PSDU");
1707  return;
1708  }
1709 
1710  NS_LOG_DEBUG ("Received QoS Null frames in a TB PPDU from " << sender);
1711 
1712  // remove the sender from the set of stations that are expected to send a TB PPDU
1713  m_staExpectTbPpduFrom.erase (sender);
1714 
1715  if (m_staExpectTbPpduFrom.empty ())
1716  {
1717  // we do not expect any other response
1718  m_txTimer.Cancel ();
1719  m_channelAccessManager->NotifyAckTimeoutResetNow ();
1720 
1721  NS_ASSERT (m_edca != 0);
1722  m_psduMap.clear ();
1723  m_edca->ResetCw ();
1724  TransmissionSucceeded ();
1725  }
1726 
1727  // the received TB PPDU has been processed
1728  return;
1729  }
1730 
1731  if (m_triggerFrameInAmpdu)
1732  {
1733  // the received A-MPDU contains a Trigger Frame. It is now time to handle it.
1734  auto psduIt = psdu->begin ();
1735  while (psduIt != psdu->end ())
1736  {
1737  if ((*psduIt)->GetHeader ().IsTrigger ())
1738  {
1739  ReceiveMpdu (*psduIt, rxSignalInfo, txVector, false);
1740  }
1741  psduIt++;
1742  }
1743 
1744  m_triggerFrameInAmpdu = false;
1745  return;
1746  }
1747 
1748  // the received frame cannot be handled here
1749  VhtFrameExchangeManager::EndReceiveAmpdu (psdu, rxSignalInfo, txVector, perMpduStatus);
1750 }
1751 
1752 } //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:172
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:241
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:57
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:332
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:385
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:245
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:239
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:291
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::QosTxop::GetNextMpdu
Ptr< WifiMacQueueItem > GetNextMpdu(Ptr< const WifiMacQueueItem > peekedItem, WifiTxParameters &txParams, Time availableTime, bool initialFrame, WifiMacQueueItem::QueueIteratorPair &queueIt)
Prepare the frame to transmit starting from the MPDU that has been previously peeked by calling PeekN...
Definition: qos-txop.cc:435
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:353
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:63
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:381
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:164
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:182
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:609
ns3::Ptr
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:74
ns3::WifiTxVector::SetLength
void SetLength(uint16_t length)
Set the LENGTH field of the L-SIG.
Definition: wifi-tx-vector.cc:321
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:659
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:263
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:420
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:369
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::WifiMacQueueItem::QueueIteratorPair
Information needed to remove an MSDU from the queue.
Definition: wifi-mac-queue-item.h:147
ns3::QosTxop::PrepareBlockAckRequest
Ptr< const WifiMacQueueItem > PrepareBlockAckRequest(Mac48Address recipient, uint8_t tid) const
Definition: qos-txop.cc:263
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:578
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:940
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::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:410
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:514
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:285
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:309
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:93
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:192
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:841
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:872
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:375
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:684
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:1137
ns3::FrameExchangeManager::NormalAckTimeout
void NormalAckTimeout(Ptr< WifiMacQueueItem > mpdu, const WifiTxVector &txVector)
Called when the Ack timeout expires.
Definition: frame-exchange-manager.cc:768
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