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