22 #include "ns3/abort.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"
34 #undef NS_LOG_APPEND_CONTEXT
35 #define NS_LOG_APPEND_CONTEXT std::clog << "[mac=" << m_self << "] "
46 static TypeId tid =
TypeId (
"ns3::HeFrameExchangeManager")
48 .AddConstructor<HeFrameExchangeManager> ()
49 .SetGroupName (
"Wifi")
55 : m_triggerFrameInAmpdu (false)
69 if (
m_mac->GetHeConfiguration ()->GetMpduBufferSize () > 64)
102 "A Multi-User Scheduler can only be aggregated to an AP");
104 "A Multi-User Scheduler can only be aggregated to an HE AP");
126 || (mpdu->GetHeader ().IsQosData ()
127 && !mpdu->GetHeader ().GetAddr1 ().IsGroup ()
130 txFormat =
m_muScheduler->NotifyAccessGranted (edca, availableTime, initialFrame);
142 NS_LOG_DEBUG (
"The Multi-user Scheduler returned DL_MU_TX with empty psduMap, do not transmit");
153 auto packet = Create<Packet> ();
155 auto trigger = Create<WifiMacQueueItem> (packet,
m_muScheduler->GetUlMuInfo ().macHdr);
175 NS_LOG_DEBUG (
"Block Ack Manager returned no frame to send");
179 if (peekedItem->GetHeader ().IsBlockAckReq ())
185 NS_ASSERT (peekedItem->GetHeader ().IsTrigger ());
200 #ifdef NS3_BUILD_PROFILE_DEBUG
205 for (
const auto& psdu : psduMap)
207 for (
const auto& mpdu : *
PeekPointer (psdu.second))
209 NS_ASSERT (mpdu->GetHeader ().IsCtl () || !mpdu->GetHeader ().HasData () || mpdu->IsQueued ());
248 auto it = std::find_if (psduMap.begin (), psduMap.end (),
250 { return psdu.second->GetAddr1 () == to; });
251 if (it != psduMap.end ())
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 ();
322 mpdu = *psdu->
begin ();
345 std::map<uint16_t, CtrlBAckRequestHeader> recipients;
353 uint16_t staId =
m_apMac->GetAssociationId (staIt->first);
356 recipients.emplace (staId, staIt->second.barHeader);
423 { return psdu.second->GetAddr1 () == station.first; });
427 std::vector<Ptr<WifiMacQueueItem>> mpduList (psduMapIt->second->begin (), psduMapIt->second->end ());
428 NS_ASSERT (mpduList.size () == psduMapIt->second->GetNMpdus ());
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));
436 station.second.blockAckTxVector.GetHeMuUserInfo (psduMapIt->first));
440 responseTxVector = &acknowledgment->stationsReplyingWithBlockAck.begin ()->second.blockAckTxVector;
450 && (mpdu = *m_psduMap.begin ()->second->begin ())->GetHeader ().IsTrigger ());
455 m_staExpectTbPpduFrom.clear ();
459 m_staExpectTbPpduFrom.insert (station.first.first);
472 m_phy->GetPhyBand ());
478 m_trigVector = GetTrigVector (m_muScheduler->GetUlMuInfo ().trigger);
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 ())
488 CtrlTriggerHeader& trigger = m_muScheduler->GetUlMuInfo ().trigger;
493 m_staExpectTbPpduFrom.clear ();
495 for (
const auto& userInfo : trigger)
497 auto staIt = m_apMac->GetStaList ().find (userInfo.GetAid12 ());
498 NS_ASSERT (staIt != m_apMac->GetStaList ().end ());
499 m_staExpectTbPpduFrom.insert (staIt->second);
504 WifiNoAck* acknowledgment =
static_cast<WifiNoAck*
> (m_txParams.m_acknowledgment.get ());
505 txVector = trigger.GetHeTbTxVector (trigger.begin ()->GetAid12 ());
509 m_phy->GetPhyBand ());
512 responseTxVector = &txVector;
513 m_trigVector = GetTrigVector (m_muScheduler->GetUlMuInfo ().trigger);
518 else if (m_txParams.m_txVector.IsUlMu ()
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;
531 else if (m_txParams.m_txVector.IsUlMu ()
538 NS_ABORT_MSG (
"Unable to handle the selected acknowledgment method ("
539 << m_txParams.m_acknowledgment.get () <<
")");
544 for (
const auto& psdu : m_psduMap)
546 psduMap.emplace (psdu.first, psdu.second);
550 if (m_txParams.m_txVector.IsUlMu ())
553 m_txParams.m_txVector,
554 m_phy->GetPhyBand ());
558 txDuration = m_phy->CalculateTxDuration (psduMap, m_txParams.m_txVector, m_phy->GetPhyBand ());
561 Time durationId = GetPsduDurationId (txDuration, m_txParams);
562 for (
auto& psdu : m_psduMap)
564 psdu.second->SetDuration (durationId);
570 if (!m_txParams.m_txVector.IsUlMu ())
577 Time timeout = txDuration + m_phy->GetSifs () + m_phy->GetSlot ()
578 + m_phy->CalculatePhyPreambleAndHeaderDuration (*responseTxVector);
579 m_channelAccessManager->NotifyAckTimeoutStartNow (
timeout);
587 this, mpdu, m_txParams.m_txVector);
592 this, psdu, m_txParams.m_txVector);
596 &m_psduMap, &m_staExpectTbPpduFrom, m_staExpectTbPpduFrom.size ());
601 &m_psduMap, &m_staExpectTbPpduFrom, m_staExpectTbPpduFrom.size ());
605 this, m_psduMap.begin ()->second, m_txParams.m_txVector);
614 ForwardPsduMapDown (psduMap, m_txParams.m_txVector);
622 hePhy->SetTrigVector (m_trigVector, m_txTimer.GetDelayLeft ());
625 && m_txParams.m_txVector.IsUlMu ())
637 for (
const auto& psdu : psduMap)
639 NS_LOG_DEBUG (
"Transmitting: [STAID=" << psdu.first <<
", " << *psdu.second <<
"]");
642 for (
const auto& psdu : psduMap)
644 NotifyTxToEdca (psdu.second);
646 if (psduMap.size () > 1 || psduMap.begin ()->second->IsAggregate () || psduMap.begin ()->second->IsSingle ())
651 m_phy->Send (psduMap, txVector);
655 HeFrameExchangeManager::PrepareMuBar (
const WifiTxVector& responseTxVector,
656 std::map<uint16_t, CtrlBAckRequestHeader> recipients)
const
663 SetTargetRssi (muBar);
669 for (
auto& userInfo : muBar)
671 auto recipientIt = recipients.find (userInfo.GetAid12 ());
672 NS_ASSERT (recipientIt != recipients.end ());
675 userInfo.SetMuBarTriggerDepUserInfo (recipientIt->second);
687 rxAddress = Mac48Address::GetBroadcast ();
692 rxAddress = m_apMac->GetStaList ().at (recipients.begin ()->first);
704 return Create<WifiMacQueueItem> (bar, hdr);
716 if (acknowledgment->
method == WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE)
729 duration += m_phy->GetSifs ()
730 + m_phy->CalculateTxDuration (
GetAckSize (), info.ackTxVector, m_phy->GetPhyBand ());
736 duration += m_phy->GetSifs ()
738 info.blockAckTxVector, m_phy->GetPhyBand ());
743 const auto& info = stations.second;
744 duration += m_phy->GetSifs ()
746 info.blockAckReqTxVector, m_phy->GetPhyBand ())
749 info.blockAckTxVector, m_phy->GetPhyBand ());
757 else if (acknowledgment->
method == WifiAcknowledgment::DL_MU_TF_MU_BAR)
766 const auto& info = stations.second;
767 NS_ASSERT (info.blockAckTxVector.GetHeMuUserInfoMap ().size () == 1);
768 uint16_t staId = info.blockAckTxVector.GetHeMuUserInfoMap ().begin ()->first;
770 info.blockAckTxVector,
771 m_phy->GetPhyBand (),
774 if (currBlockAckDuration > duration)
776 duration = currBlockAckDuration;
783 std::tie (dlMuTfMuBarAcknowledgment->
ulLength, duration) = HePhy::ConvertHeTbPpduDurationToLSigLength (duration, txVector, m_phy->GetPhyBand ());
789 muBarSize = MpduAggregator::GetSizeIfAggregated (muBarSize, 0);
792 + m_phy->CalculateTxDuration (muBarSize,
794 m_phy->GetPhyBand ())
795 + m_phy->GetSifs () + duration;
800 else if (acknowledgment->
method == WifiAcknowledgment::DL_MU_AGGREGATE_TF)
809 const auto& info = stations.second;
810 NS_ASSERT (info.blockAckTxVector.GetHeMuUserInfoMap ().size () == 1);
811 uint16_t staId = info.blockAckTxVector.GetHeMuUserInfoMap ().begin ()->first;
813 info.blockAckTxVector,
814 m_phy->GetPhyBand (),
817 if (currBlockAckDuration > duration)
819 duration = currBlockAckDuration;
826 std::tie (dlMuAggrTfAcknowledgment->
ulLength, duration) = HePhy::ConvertHeTbPpduDurationToLSigLength (duration, txVector, m_phy->GetPhyBand ());
832 else if (acknowledgment->
method == WifiAcknowledgment::UL_MU_MULTI_STA_BA)
838 m_phy->GetPhyBand ());
844 else if (acknowledgment->
method == WifiAcknowledgment::ACK_AFTER_TB_PPDU)
853 VhtFrameExchangeManager::CalculateAcknowledgmentTime (acknowledgment);
858 HeFrameExchangeManager::GetTxDuration (uint32_t ppduPayloadSize,
Mac48Address receiver,
863 return VhtFrameExchangeManager::GetTxDuration (ppduPayloadSize, receiver, txParams);
870 && txParams.
m_acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF)
878 ppduPayloadSize = MpduAggregator::GetSizeIfAggregated (info->second.muBarSize, ppduPayloadSize);
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);
891 const std::set<Mac48Address>* staMissedTbPpduFrom,
892 std::size_t nSolicitedStations)
894 NS_LOG_FUNCTION (
this << psduMap << staMissedTbPpduFrom->size () << nSolicitedStations);
898 && psduMap->begin ()->second->GetHeader (0).IsTrigger ());
901 NS_ASSERT (!staMissedTbPpduFrom->empty ());
904 if (staMissedTbPpduFrom->size () == nSolicitedStations)
907 m_edca->UpdateFailedCw ();
909 TransmissionFailed ();
911 else if (!m_multiStaBaEvent.IsRunning ())
914 TransmissionSucceeded ();
921 HeFrameExchangeManager::BlockAcksInTbPpduTimeout (
WifiPsduMap* psduMap,
922 const std::set<Mac48Address>* staMissedBlockAckFrom,
923 std::size_t nSolicitedStations)
929 && (m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF
930 || m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_TF_MU_BAR));
933 NS_ASSERT (!staMissedBlockAckFrom->empty ());
937 if (staMissedBlockAckFrom->size () == nSolicitedStations)
941 m_mac->GetWifiRemoteStationManager ()->ReportDataFailed (*psduMap->begin ()->second->begin ());
950 m_triggerFrame =
nullptr;
952 for (
const auto& sta : *staMissedBlockAckFrom)
961 MissedBlockAck (psdu, m_txParams.m_txVector, psduResetCw);
962 resetCw = resetCw || psduResetCw;
973 m_edca->UpdateFailedCw ();
976 if (staMissedBlockAckFrom->size () == nSolicitedStations)
979 TransmissionFailed ();
983 TransmissionSucceeded ();
996 m_mac->GetWifiRemoteStationManager ()->ReportDataFailed (*psdu->
begin ());
998 MissedBlockAck (psdu, m_txParams.m_txVector, resetCw);
1013 VhtFrameExchangeManager::NormalAckTimeout (mpdu, txVector);
1018 for (
auto& psdu : m_psduMap)
1022 if (mpdu->IsQueued ())
1024 mpdu->GetHeader ().SetRetry ();
1036 VhtFrameExchangeManager::BlockAckTimeout (psdu, txVector);
1041 for (
auto& psdu : m_psduMap)
1045 if (mpdu->IsQueued ())
1047 mpdu->GetHeader ().SetRetry ();
1062 for (
const auto& userInfoField : trigger)
1065 {userInfoField.GetRuAllocation (),
1066 HePhy::GetHeMcs (userInfoField.GetUlMcs ()),
1067 userInfoField.GetNss ()});
1077 uint16_t staId = m_staMac->GetAssociationId ();
1084 NS_ASSERT_MSG (heConfiguration != 0,
"This STA has to be an HE station to send an HE TB PPDU");
1087 uint8_t powerLevel = m_mac->GetWifiRemoteStationManager ()->GetDefaultTxPowerLevel ();
1105 int8_t pathLossDb = trigger.
GetApTxPower () -
static_cast<int8_t
> (m_mac->GetWifiRemoteStationManager ()->GetMostRecentRssi (triggerSender));
1106 double reqTxPowerDbm =
static_cast<double> (userInfoIt->GetUlTargetRssi () + pathLossDb);
1109 uint8_t numPowerLevels = m_phy->GetNTxPower ();
1110 if (numPowerLevels > 1)
1112 double stepDbm = (m_phy->GetTxPowerEnd () - m_phy->GetTxPowerStart ()) / (numPowerLevels - 1);
1113 powerLevel =
static_cast<uint8_t
> (ceil ((reqTxPowerDbm - m_phy->GetTxPowerStart ()) / stepDbm));
1114 if (powerLevel > numPowerLevels)
1116 powerLevel = numPowerLevels;
1119 if (reqTxPowerDbm > m_phy->GetPowerDbm (powerLevel))
1121 NS_LOG_WARN (
"The requested power level (" << reqTxPowerDbm <<
"dBm) cannot be satisfied (max: " << m_phy->GetTxPowerEnd () <<
"dBm)");
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 <<
"}");
1138 trigger.
SetApTxPower (
static_cast<int8_t
> (m_phy->GetPowerDbm (m_mac->GetWifiRemoteStationManager ()->GetDefaultTxPowerLevel ())));
1139 for (
auto& userInfo : trigger)
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);
1146 userInfo.SetUlTargetRssi (rssi);
1157 && txParams.
m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
1169 receiver = staInfo.first.first;
1170 uint8_t tid = staInfo.first.second;
1171 std::size_t index = staInfo.second;
1173 blockAck.
SetAid11 (m_apMac->GetAssociationId (receiver), index);
1179 NS_LOG_DEBUG (
"Multi-STA Block Ack: Sending All-ack to=" << receiver);
1187 NS_LOG_DEBUG (
"Multi-STA Block Ack: Sending Ack to=" << receiver);
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);
1200 <<
" to=" << receiver <<
" tid=" << +tid);
1213 Ptr<WifiPsdu> psdu = GetWifiPsdu (Create<WifiMacQueueItem> (packet, hdr),
1221 m_phy->GetPhyBand ());
1226 psdu->
SetDuration (GetPsduDurationId (txDuration, params));
1235 m_muSnrTag.Reset ();
1236 Simulator::Schedule (txDuration, &HeFrameExchangeManager::TransmissionSucceeded,
this);
1244 NS_ASSERT (m_staMac != 0 && m_staMac->IsAssociated ());
1246 NS_LOG_DEBUG (
"Received a Trigger Frame (basic variant) soliciting a transmission");
1250 NS_LOG_DEBUG (
"Carrier Sensing required and channel busy, do nothing");
1260 std::vector<uint8_t> tids;
1261 uint16_t staId = m_staMac->GetAssociationId ();
1264 for (uint8_t i = 0; i < 4; i++)
1267 tids.push_back (acIt->second.GetHighTid ());
1268 tids.push_back (acIt->second.GetLowTid ());
1281 Time ppduDuration = HePhy::ConvertLSigLengthToHeTbPpduDuration (trigger.
GetUlLength (),
1283 m_phy->GetPhyBand ());
1285 for (
const auto& tid : tids)
1300 && TryAddMpdu (mpdu, txParams, ppduDuration))
1315 std::vector<Ptr<WifiMacQueueItem>> mpduList = m_mpduAggregator->GetNextAmpdu (item, txParams,
1317 psdu = (mpduList.size () > 1 ? Create<WifiPsdu> (std::move (mpduList))
1318 : Create<WifiPsdu> (item,
true));
1327 SendPsduMapWithProtection (
WifiPsduMap {{staId, psdu}}, txParams);
1332 SendQosNullFramesInTbPpdu (trigger, hdr);
1341 NS_ASSERT (m_staMac != 0 && m_staMac->IsAssociated ());
1348 <<
", TxopHolder=" << m_txopHolder <<
", NAV end=" << m_navEnd.As (Time::S)
1349 <<
"), do nothing");
1371 Time ppduDuration = HePhy::ConvertLSigLengthToHeTbPpduDuration (trigger.
GetUlLength (),
1373 m_phy->GetPhyBand ());
1377 std::vector<Ptr<WifiMacQueueItem>> mpduList;
1382 && IsWithinSizeAndTimeLimits (txParams.
GetSizeIfAddMpdu (mpdu = Create<WifiMacQueueItem> (Create<Packet> (),
1384 hdr.
GetAddr2 (), txParams, ppduDuration))
1386 NS_LOG_DEBUG (
"Aggregating a QoS Null frame with tid=" << +tid);
1394 UpdateTxDuration (mpdu->GetHeader ().GetAddr1 (), txParams);
1395 mpduList.push_back (mpdu);
1399 if (mpduList.empty ())
1401 NS_LOG_DEBUG (
"Not enough time to send a QoS Null frame");
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);
1420 else if (!txVector.
IsUlMu ())
1422 VhtFrameExchangeManager::SetTxopHolder (psdu, txVector);
1431 NS_ASSERT (mpdu->GetHeader ().GetAddr1 ().IsGroup ()
1432 || mpdu->GetHeader ().GetAddr1 () == m_self);
1436 if (txVector.
IsUlMu () && m_txTimer.IsRunning ()
1437 && m_txTimer.GetReason () == WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF)
1441 && m_txParams.m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
1445 if (m_staExpectTbPpduFrom.find (sender) == m_staExpectTbPpduFrom.end ())
1447 NS_LOG_WARN (
"Received a TB PPDU from an unexpected station: " << sender);
1453 NS_LOG_DEBUG (
"Received a BlockAckReq in a TB PPDU from " << sender);
1456 mpdu->GetPacket ()->PeekHeader (blockAckReq);
1459 auto agreementIt = m_agreements.find ({sender, tid});
1460 NS_ASSERT (agreementIt != m_agreements.end ());
1465 acknowledgment->
baType.
m_bitmapLen.push_back (GetBlockAckType (sender, tid).m_bitmapLen.at (0));
1467 m_muSnrTag.Set (staId, rxSignalInfo.
snr);
1471 NS_LOG_DEBUG (
"Received an S-MPDU in a TB PPDU from " << sender <<
" (" << *mpdu <<
")");
1474 auto agreementIt = m_agreements.find ({sender, tid});
1475 NS_ASSERT (agreementIt != m_agreements.end ());
1476 agreementIt->second.NotifyReceivedMpdu (mpdu);
1482 m_muSnrTag.Set (staId, rxSignalInfo.
snr);
1491 VhtFrameExchangeManager::ReceiveMpdu (mpdu, rxSignalInfo, txVector, inAmpdu);
1498 m_multiStaBaEvent = Simulator::Schedule (m_phy->GetSifs (),
1499 &HeFrameExchangeManager::SendMultiStaBlockAck,
1500 this, std::cref (m_txParams));
1504 m_staExpectTbPpduFrom.erase (sender);
1506 if (m_staExpectTbPpduFrom.empty ())
1509 m_txTimer.Cancel ();
1510 m_channelAccessManager->NotifyAckTimeoutResetNow ();
1512 if (!m_multiStaBaEvent.IsRunning ())
1518 TransmissionSucceeded ();
1528 if (hdr.
IsCts () && m_txTimer.IsRunning () && m_txTimer.GetReason () == WifiTxTimer::WAIT_CTS
1529 && m_psduMap.size () == 1)
1534 Mac48Address sender = m_psduMap.begin ()->second->GetAddr1 ();
1538 mpdu->GetPacket ()->PeekPacketTag (tag);
1539 m_mac->GetWifiRemoteStationManager ()->ReportRxOk (sender, rxSignalInfo, txVector);
1540 m_mac->GetWifiRemoteStationManager ()->ReportRtsOk (m_psduMap.begin ()->second->GetHeader (0),
1543 m_txTimer.Cancel ();
1544 m_channelAccessManager->NotifyCtsTimeoutResetNow ();
1545 Simulator::Schedule (m_phy->GetSifs (), &HeFrameExchangeManager::SendPsduMap,
this);
1547 else if (hdr.
IsAck () && m_txTimer.IsRunning ()
1548 && m_txTimer.GetReason () == WifiTxTimer::WAIT_NORMAL_ACK_AFTER_DL_MU_PPDU)
1551 NS_ASSERT (m_txParams.m_acknowledgment);
1552 NS_ASSERT (m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE);
1558 auto it = m_psduMap.find (staId);
1562 mpdu->GetPacket ()->PeekPacketTag (tag);
1563 ReceivedNormalAck (*it->second->begin (), m_txParams.m_txVector, txVector, rxSignalInfo, tag.
Get ());
1573 && m_txTimer.GetReason () == WifiTxTimer::WAIT_BLOCK_ACKS_IN_TB_PPDU)
1576 NS_LOG_DEBUG (
"Received BlockAck in TB PPDU from=" << sender);
1579 mpdu->GetPacket ()->PeekPacketTag (tag);
1583 mpdu->GetPacket ()->PeekHeader (blockAck);
1585 std::pair<uint16_t,uint16_t> ret = GetBaManager (tid)->NotifyGotBlockAck (blockAck, hdr.
GetAddr2 (),
1587 m_mac->GetWifiRemoteStationManager ()->ReportAmpduTxStatus (hdr.
GetAddr2 (), ret.first, ret.second,
1588 rxSignalInfo.
snr, tag.
Get (), m_txParams.m_txVector);
1591 if (m_staExpectTbPpduFrom.erase (sender) == 0)
1593 NS_LOG_WARN (
"Received a BlockAck from an unexpected stations: " << sender);
1597 if (m_staExpectTbPpduFrom.empty ())
1600 m_txTimer.Cancel ();
1601 m_channelAccessManager->NotifyAckTimeoutResetNow ();
1602 m_triggerFrame =
nullptr;
1606 TransmissionSucceeded ();
1609 else if (hdr.
IsBlockAck () && m_txTimer.IsRunning ()
1610 && m_txTimer.GetReason () == WifiTxTimer::WAIT_BLOCK_ACK_AFTER_TB_PPDU)
1613 mpdu->GetPacket ()->PeekHeader (blockAck);
1616 "A Multi-STA BlockAck is expected after a TB PPDU");
1619 NS_ASSERT (m_staMac !=
nullptr && m_staMac->IsAssociated ());
1622 NS_LOG_DEBUG (
"The sender is not the AP we are associated with");
1626 uint16_t staId = m_staMac->GetAssociationId ();
1629 if (indices.empty ())
1631 NS_LOG_DEBUG (
"No Per AID TID Info subfield intended for me");
1636 mpdu->GetPacket ()->PeekPacketTag (tag);
1639 for (
const auto& index : indices)
1646 NS_ABORT_IF (m_psduMap.empty () || m_psduMap.begin ()->first != staId);
1647 GetBaManager (tid)->NotifyGotAck (*m_psduMap.at (staId)->begin ());
1652 if (blockAck.
GetAckType (index) && tid == 14)
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 ();
1662 std::pair<uint16_t,uint16_t> ret = GetBaManager (tid)->NotifyGotBlockAck (blockAck,
1665 m_mac->GetWifiRemoteStationManager ()->ReportAmpduTxStatus (hdr.
GetAddr2 (), ret.first,
1666 ret.second, rxSignalInfo.
snr,
1667 tag.
Get (staId), m_txParams.m_txVector);
1670 if (m_psduMap.at (staId)->GetHeader (0).IsQosData ()
1672 || std::any_of (blockAck.
GetBitmap (index).begin (),
1674 [](uint8_t b) { return b != 0; })))
1676 NS_ASSERT (m_psduMap.at (staId)->GetHeader (0).HasData ());
1677 NS_ASSERT (m_psduMap.at (staId)->GetHeader (0).GetQosTid () == tid);
1682 m_mac->GetQosTxop (tid)->StartMuEdcaTimerNow ();
1687 m_txTimer.Cancel ();
1688 m_channelAccessManager->NotifyAckTimeoutResetNow ();
1691 else if (hdr.
IsBlockAck () && m_txTimer.IsRunning ()
1692 && m_txTimer.GetReason () == WifiTxTimer::WAIT_BLOCK_ACK)
1698 VhtFrameExchangeManager::ReceiveMpdu (mpdu, rxSignalInfo, txVector, inAmpdu);
1703 if (m_staMac ==
nullptr)
1711 m_triggerFrameInAmpdu =
true;
1716 mpdu->GetPacket ()->PeekHeader (trigger);
1720 || !m_staMac->IsAssociated ()
1728 uint16_t staId = m_staMac->GetAssociationId ();
1733 NS_LOG_DEBUG (
"Received MU-BAR Trigger Frame from=" << sender);
1734 m_mac->GetWifiRemoteStationManager ()->ReportRxOk (sender, rxSignalInfo, txVector);
1742 auto agreementIt = m_agreements.find ({sender, tid});
1744 if (agreementIt == m_agreements.end ())
1746 NS_LOG_DEBUG (
"There's not a valid agreement for this BlockAckReq");
1753 Simulator::Schedule (m_phy->GetSifs (), &HeFrameExchangeManager::SendBlockAck,
this,
1755 GetHeTbTxVector (trigger, hdr.
GetAddr2 ()), rxSignalInfo.
snr);
1759 Simulator::Schedule (m_phy->GetSifs (), &HeFrameExchangeManager::ReceiveBasicTrigger,
1760 this, trigger, hdr);
1762 else if (trigger.
IsBsrp ())
1764 Simulator::Schedule (m_phy->GetSifs (), &HeFrameExchangeManager::SendQosNullFramesInTbPpdu,
1765 this, trigger, hdr);
1771 VhtFrameExchangeManager::ReceiveMpdu (mpdu, rxSignalInfo, txVector, inAmpdu);
1779 VhtFrameExchangeManager::ReceiveMpdu (mpdu, rxSignalInfo, txVector, inAmpdu);;
1784 const WifiTxVector& txVector,
const std::vector<bool>& perMpduStatus)
1786 std::set<uint8_t> tids = psdu->
GetTids ();
1788 if (txVector.
IsUlMu () && m_txTimer.IsRunning ()
1789 && m_txTimer.GetReason () == WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF)
1793 && m_txParams.m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
1797 if (m_staExpectTbPpduFrom.find (sender) == m_staExpectTbPpduFrom.end ())
1799 NS_LOG_WARN (
"Received a TB PPDU from an unexpected station: " << sender);
1803 NS_LOG_DEBUG (
"Received an A-MPDU in a TB PPDU from " << sender <<
" (" << *psdu <<
")");
1805 if (std::any_of (tids.begin (), tids.end (),
1806 [&psdu](uint8_t tid)
1807 { return psdu->GetAckPolicyForTid (tid) == WifiMacHeader::NORMAL_ACK; }))
1809 if (std::all_of (perMpduStatus.cbegin (), perMpduStatus.cend (), [](
bool v) { return v; }))
1819 for (
const auto& tid : tids)
1822 acknowledgment->
baType.
m_bitmapLen.push_back (GetBlockAckType (sender, tid).m_bitmapLen.at (0));
1826 m_muSnrTag.Set (staId, rxSignalInfo.
snr);
1832 m_multiStaBaEvent = Simulator::Schedule (m_phy->GetSifs (),
1833 &HeFrameExchangeManager::SendMultiStaBlockAck,
1834 this, std::cref (m_txParams));
1838 m_staExpectTbPpduFrom.erase (sender);
1840 if (m_staExpectTbPpduFrom.empty ())
1843 m_txTimer.Cancel ();
1844 m_channelAccessManager->NotifyAckTimeoutResetNow ();
1846 if (!m_multiStaBaEvent.IsRunning ())
1852 TransmissionSucceeded ();
1860 if (txVector.
IsUlMu () && m_txTimer.IsRunning ()
1861 && m_txTimer.GetReason () == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF)
1865 if (m_staExpectTbPpduFrom.find (sender) == m_staExpectTbPpduFrom.end ())
1867 NS_LOG_WARN (
"Received a TB PPDU from an unexpected station: " << sender);
1871 { return mpdu->GetHeader ().IsQosData ()
1872 && !mpdu->GetHeader ().HasData ();
1875 NS_LOG_WARN (
"No QoS Null frame in the received PSDU");
1879 NS_LOG_DEBUG (
"Received QoS Null frames in a TB PPDU from " << sender);
1882 m_staExpectTbPpduFrom.erase (sender);
1884 if (m_staExpectTbPpduFrom.empty ())
1887 m_txTimer.Cancel ();
1888 m_channelAccessManager->NotifyAckTimeoutResetNow ();
1893 TransmissionSucceeded ();
1900 if (m_triggerFrameInAmpdu)
1903 auto psduIt = psdu->
begin ();
1904 while (psduIt != psdu->
end ())
1906 if ((*psduIt)->GetHeader ().IsTrigger ())
1908 ReceiveMpdu (*psduIt, rxSignalInfo, txVector,
false);
1913 m_triggerFrameInAmpdu =
false;
1918 VhtFrameExchangeManager::EndReceiveAmpdu (psdu, rxSignalInfo, txVector, perMpduStatus);
void Cancel(void)
This method is syntactic sugar for the ns3::Simulator::Cancel method.
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.
virtual ~HeFrameExchangeManager()
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)
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.
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...
double Get(uint16_t staId) const
Return the SNR value for the given sender.
TxFormat
Enumeration of the possible transmission formats.
void AddHeader(const Header &header)
Add header to this packet.
void AddPacketTag(const Tag &tag) const
Add a packet tag.
Smart pointer class similar to boost::intrusive_ptr.
Ptr< QosTxop > m_edca
the EDCAF that gained channel access
bool GetBaAgreementEstablished(Mac48Address address, uint8_t tid) const
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...
Ptr< BlockAckManager > GetBaManager(void)
Get the Block Ack Manager associated with this QosTxop.
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.
void ScheduleBar(Ptr< const WifiMacQueueItem > bar, bool skipIfNoDataQueued=false)
static EventId Schedule(Time const &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Introspection did not find any typical Config paths.
double Get(void) const
Return the SNR value.
Simulation virtual time values and global simulation resolution.
static Time Min()
Minimum representable Time Not to be confused with Min(Time,Time).
a unique identifier for an interface.
TypeId SetParent(TypeId tid)
Set the parent TypeId.
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.
WifiPhyBand GetPhyBand(void) const
Get the configured Wi-Fi band.
Time GetSlot(void) const
Return the slot duration for this PHY.
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Ptr< PhyEntity > GetPhyEntity(WifiModulationClass modulation) const
Get the supported PHY entity corresponding to the modulation class, for the WifiPhy instance.
Time GetSifs(void) const
Return the Short Interframe Space (SIFS) for this PHY.
static Time CalculatePhyPreambleAndHeaderDuration(const WifiTxVector &txVector)
uint32_t GetSize(void) const
Return the size of the PSDU in bytes.
std::vector< Ptr< WifiMacQueueItem > >::const_iterator begin(void) const
Return a const iterator to the first MPDU.
const WifiMacHeader & GetHeader(std::size_t i) const
Get the header of the i-th MPDU.
std::size_t GetNMpdus(void) const
Return the number of MPDUs constituting the PSDU.
std::vector< Ptr< WifiMacQueueItem > >::const_iterator end(void) const
Return a const iterator to past-the-last MPDU.
Ptr< const Packet > GetPayload(std::size_t i) const
Get the payload of the i-th MPDU.
Mac48Address GetAddr2(void) const
Get the Transmitter Address (TA), which is common to all the MPDUs.
void SetDuration(Time duration)
Set the Duration/ID field on all the MPDUs.
Mac48Address GetAddr1(void) const
Get the Receiver Address (RA), which is common to all the MPDUs.
std::set< uint8_t > GetTids(void) const
Get the set of TIDs of the QoS Data frames included in the PSDU.
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.
@ WAIT_BLOCK_ACK_AFTER_TB_PPDU
@ WAIT_NORMAL_ACK_AFTER_DL_MU_PPDU
@ WAIT_QOS_NULL_AFTER_BSRP_TF
@ WAIT_TB_PPDU_AFTER_BASIC_TF
@ WAIT_BLOCK_ACKS_IN_TB_PPDU
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,...
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
#define NS_ABORT_IF(cond)
Abnormal program termination if a condition is true.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
#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.
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Time Now(void)
create an ns3::Time instance which contains the current simulation time.
Time Seconds(double value)
Construct a Time in the indicated unit.
AcIndex
This enumeration defines the Access Categories as an enumeration with values corresponding to the AC ...
@ WIFI_MOD_CLASS_VHT
VHT (Clause 22)
@ WIFI_MOD_CLASS_HE
HE (Clause 27)
Declaration of ns3::HePhy class and ns3::HeSigAParameters struct.
void(* Time)(Time oldValue, Time newValue)
TracedValue callback signature for Time.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
uint32_t GetAckSize(void)
Return the total Ack size (including FCS trailer).
uint32_t GetBlockAckRequestSize(BlockAckReqType type)
Return the total BlockAckRequest size (including FCS trailer).
uint32_t GetMuBarSize(std::list< BlockAckReqType > types)
Return the total MU-BAR size (including FCS trailer).
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...
uint32_t GetBlockAckSize(BlockAckType type)
Return the total BlockAck size (including FCS trailer).
std::unordered_map< uint16_t, Ptr< WifiPsdu > > WifiPsduMap
Map of PSDUs indexed by STA-ID.
U * PeekPointer(const Ptr< U > &p)
Ptr< T > Copy(Ptr< T > object)
Return a deep copy of a Ptr.
std::vector< uint8_t > m_bitmapLen
Length (bytes) of included bitmaps.
RxSignalInfo structure containing info on the received signal.
double snr
SNR in linear scale.
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.