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