16#include "ns3/ap-wifi-mac.h"
17#include "ns3/erp-ofdm-phy.h"
19#include "ns3/recipient-block-ack-agreement.h"
20#include "ns3/snr-tag.h"
21#include "ns3/sta-wifi-mac.h"
22#include "ns3/wifi-mac-queue.h"
23#include "ns3/wifi-mac-trailer.h"
28#undef NS_LOG_APPEND_CONTEXT
29#define NS_LOG_APPEND_CONTEXT WIFI_FEM_NS_LOG_APPEND_CONTEXT
41 return psduMap.size() == 1 && psduMap.cbegin()->first ==
SU_STA_ID &&
42 psduMap.cbegin()->second->GetNMpdus() == 1 &&
43 psduMap.cbegin()->second->GetHeader(0).IsTrigger();
49 return psduMap.size() == 1 && psduMap.cbegin()->first ==
SU_STA_ID &&
50 psduMap.cbegin()->second->GetNMpdus() == 1 &&
51 psduMap.cbegin()->second->GetHeader(0).IsTrigger();
58 TypeId(
"ns3::HeFrameExchangeManager")
60 .AddConstructor<HeFrameExchangeManager>()
62 .AddAttribute(
"ContinueTxopAfterBsrp",
63 "Whether to continue a TXOP a SIFS after the reception of responses "
64 "to a BSRP Trigger Frame when TXOP limit is zero.",
72 : m_intraBssNavEnd(0),
73 m_triggerFrameInAmpdu(false)
122 "A Multi-User Scheduler can only be aggregated to an HE AP");
143 (!(mpdu = edca->PeekNextMpdu(
m_linkId)) ||
144 (mpdu->GetHeader().IsQosData() && !mpdu->GetHeader().GetAddr1().IsGroup() &&
145 m_mac->GetBaAgreementEstablishedAsOriginator(mpdu->GetHeader().GetAddr1(),
146 mpdu->GetHeader().GetQosTid()))))
165 "The Multi-user Scheduler returned DL_MU_TX with empty psduMap, do not transmit");
216 <<
") incompatible with Basic Trigger Frame");
220 <<
") incompatible with BSRP Trigger Frame");
222 auto txVector = trigger.GetHeTbTxVector(trigger.begin()->GetAid12());
239 if (mpdu->IsQueued())
256 "Cannot use RTS/CTS with MU PPDUs");
273std::set<Mac48Address>
276 std::set<Mac48Address> recipients;
280 for (
const auto& userInfo : trigger)
282 const auto addressIt = aidAddrMap.find(userInfo.GetAid12());
283 NS_ASSERT_MSG(addressIt != aidAddrMap.end(),
"AID not found");
284 recipients.insert(addressIt->second);
304 NS_LOG_INFO(
"Multi-user scheduler aborted the transmission");
335 NS_LOG_FUNCTION(
this << muRtsSize << muRtsTxVector << txDuration << response);
339 const auto singleDurationId =
344 return singleDurationId;
381 protection->muRts.SetCsRequired(
true);
383 payload->AddHeader(protection->muRts);
389 mpdu->GetHeader().SetDuration(
391 protection->muRtsTxVector,
404 protection->muRtsTxVector,
416 protection->muRtsTxVector);
442 auto it = std::find_if(
445 [&to](std::pair<uint16_t,
Ptr<WifiPsdu>> psdu) { return psdu.second->GetAddr1() == to; });
446 if (it != psduMap.end())
481 NS_LOG_DEBUG(address <<
" did not respond, hence it is no longer protected");
491 NS_LOG_DEBUG(
"Schedule another transmission in a SIFS after successful BSRP TF");
494 if (!StartTransmission(m_edca, Seconds(0)))
512HeFrameExchangeManager::SendPsduMap()
524 std::set<Mac48Address> staExpectResponseFrom;
531 if (m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE)
533 auto acknowledgment =
537 for (
const auto& psdu : m_psduMap)
539 if (acknowledgment->stationsSendBlockAckReqTo.contains(psdu.second->GetAddr1()))
542 std::set<uint8_t> tids = psdu.second->GetTids();
544 "Acknowledgment method incompatible with a Multi-TID A-MPDU");
545 uint8_t tid = *tids.begin();
549 m_mac->GetQosTxop(tid)->PrepareBlockAckRequest(psdu.second->GetAddr1(), tid);
550 m_edca->GetBaManager()->ScheduleBar(reqHdr, hdr);
554 if (!acknowledgment->stationsReplyingWithNormalAck.empty())
557 timerType = WifiTxTimer::WAIT_NORMAL_ACK_AFTER_DL_MU_PPDU;
559 &acknowledgment->stationsReplyingWithNormalAck.begin()->second.ackTxVector;
560 auto from = acknowledgment->stationsReplyingWithNormalAck.begin()->first;
561 psdu = GetPsduTo(from, m_psduMap);
563 mpdu = *psdu->begin();
564 staExpectResponseFrom.insert(from);
566 else if (!acknowledgment->stationsReplyingWithBlockAck.empty())
569 timerType = WifiTxTimer::WAIT_BLOCK_ACK;
571 &acknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
572 auto from = acknowledgment->stationsReplyingWithBlockAck.begin()->first;
573 psdu = GetPsduTo(from, m_psduMap);
574 staExpectResponseFrom.insert(from);
581 else if (m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_TF_MU_BAR)
583 auto acknowledgment =
static_cast<WifiDlMuTfMuBar*
>(m_txParams.m_acknowledgment.get());
590 std::map<uint16_t, CtrlBAckRequestHeader> recipients;
592 NS_ASSERT(!acknowledgment->stationsReplyingWithBlockAck.empty());
593 auto staIt = acknowledgment->stationsReplyingWithBlockAck.begin();
594 m_trigVector = staIt->second.blockAckTxVector;
595 while (staIt != acknowledgment->stationsReplyingWithBlockAck.end())
598 uint16_t staId = m_apMac->GetAssociationId(staIt->first, m_linkId);
600 m_trigVector.SetHeMuUserInfo(staId,
601 staIt->second.blockAckTxVector.GetHeMuUserInfo(staId));
602 recipients.emplace(staId, staIt->second.barHeader);
608 m_trigVector.SetLength(acknowledgment->ulLength);
610 m_triggerFrame = PrepareMuBar(m_trigVector, recipients);
617 for (
auto& station : acknowledgment->stationsReplyingWithBlockAck)
619 staExpectResponseFrom.insert(station.first);
622 Ptr<WifiPsdu> triggerPsdu = GetWifiPsdu(m_triggerFrame, acknowledgment->muBarTxVector);
623 Time txDuration = WifiPhy::CalculateTxDuration(triggerPsdu->GetSize(),
624 acknowledgment->muBarTxVector,
625 m_phy->GetPhyBand());
627 *acknowledgment->acknowledgmentTime -= (m_phy->GetSifs() + txDuration);
628 m_triggerFrame->GetHeader().SetDuration(GetPsduDurationId(txDuration, m_txParams));
631 &acknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
632 Time timeout = txDuration + m_phy->GetSifs() + m_phy->GetSlot() +
633 WifiPhy::CalculatePhyPreambleAndHeaderDuration(*responseTxVector);
635 m_txTimer.Set(WifiTxTimer::WAIT_BLOCK_ACKS_IN_TB_PPDU,
637 staExpectResponseFrom,
638 &HeFrameExchangeManager::BlockAcksInTbPpduTimeout,
641 staExpectResponseFrom.size());
642 m_channelAccessManager->NotifyAckTimeoutStartNow(
timeout);
644 ForwardPsduDown(triggerPsdu, acknowledgment->muBarTxVector);
649 hePhy->SetTrigVector(m_trigVector,
timeout);
657 else if (m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF)
659 auto acknowledgment =
static_cast<WifiDlMuAggregateTf*
>(m_txParams.m_acknowledgment.get());
665 for (
auto& station : acknowledgment->stationsReplyingWithBlockAck)
667 staExpectResponseFrom.insert(station.first);
670 auto psduMapIt = std::find_if(m_psduMap.begin(),
673 return psdu.second->GetAddr1() == station.first;
678 std::vector<Ptr<WifiMpdu>> mpduList(psduMapIt->second->begin(),
679 psduMapIt->second->end());
680 NS_ASSERT(mpduList.size() == psduMapIt->second->GetNMpdus());
683 station.second.blockAckTxVector.SetLength(acknowledgment->ulLength);
684 mpduList.push_back(PrepareMuBar(station.second.blockAckTxVector,
685 {{psduMapIt->first, station.second.barHeader}}));
686 psduMapIt->second = Create<WifiPsdu>(std::move(mpduList));
687 m_trigVector.SetHeMuUserInfo(
689 station.second.blockAckTxVector.GetHeMuUserInfo(psduMapIt->first));
692 timerType = WifiTxTimer::WAIT_BLOCK_ACKS_IN_TB_PPDU;
694 &acknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
695 m_trigVector.
SetLength(acknowledgment->ulLength);
700 else if (m_txParams.m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA)
704 mpdu = *m_psduMap.begin()->second->begin();
706 auto acknowledgment =
static_cast<WifiUlMuMultiStaBa*
>(m_txParams.m_acknowledgment.get());
709 for (
const auto& station : acknowledgment->stationsReceivingMultiStaBa)
711 staExpectResponseFrom.insert(station.first.first);
717 acknowledgment->baType.m_bitmapLen.clear();
719 timerType = WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF;
720 responseTxVector = &acknowledgment->tbPpduTxVector;
721 m_trigVector = GetTrigVector(m_muScheduler->GetUlMuInfo(m_linkId).trigger);
726 else if (m_txParams.m_acknowledgment->method == WifiAcknowledgment::NONE &&
727 !m_txParams.m_txVector.IsUlMu() &&
IsTrigger(m_psduMap))
729 CtrlTriggerHeader& trigger = m_muScheduler->GetUlMuInfo(m_linkId).trigger;
734 for (
const auto& userInfo : trigger)
736 auto staIt = m_apMac->GetStaList(m_linkId).find(userInfo.GetAid12());
737 NS_ASSERT(staIt != m_apMac->GetStaList(m_linkId).end());
738 staExpectResponseFrom.insert(staIt->second);
741 timerType = WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF;
742 txVector = trigger.GetHeTbTxVector(trigger.begin()->GetAid12());
743 responseTxVector = &txVector;
744 m_trigVector = GetTrigVector(m_muScheduler->GetUlMuInfo(m_linkId).trigger);
749 else if (m_txParams.m_txVector.IsUlMu() &&
750 m_txParams.m_acknowledgment->method == WifiAcknowledgment::ACK_AFTER_TB_PPDU)
753 timerType = WifiTxTimer::WAIT_BLOCK_ACK_AFTER_TB_PPDU;
754 NS_ASSERT(m_staMac && m_staMac->IsAssociated());
755 auto recv = m_psduMap.begin()->second->GetAddr1();
756 txVector = GetWifiRemoteStationManager()->GetBlockAckTxVector(recv, m_txParams.m_txVector);
757 responseTxVector = &txVector;
758 staExpectResponseFrom.insert(recv);
763 else if (m_txParams.m_txVector.IsUlMu() &&
764 m_txParams.m_acknowledgment->method == WifiAcknowledgment::NONE)
770 NS_ABORT_MSG(
"Unable to handle the selected acknowledgment method ("
771 << m_txParams.m_acknowledgment.get() <<
")");
776 for (
const auto& psdu : m_psduMap)
778 psduMap.emplace(psdu.first, psdu.second);
782 if (m_txParams.m_txVector.IsUlMu())
784 txDuration = HePhy::ConvertLSigLengthToHeTbPpduDuration(m_txParams.m_txVector.GetLength(),
785 m_txParams.m_txVector,
786 m_phy->GetPhyBand());
791 WifiPhy::CalculateTxDuration(psduMap, m_txParams.m_txVector, m_phy->GetPhyBand());
794 Time durationId = GetPsduDurationId(txDuration, m_txParams);
796 if (m_continueTxopAfterBsrpTf && m_edca && m_edca->GetTxopLimit(m_linkId).IsZero() &&
797 timerType == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF)
801 durationId += m_muScheduler->GetExtraTimeForBsrpTfDurationId(m_linkId);
804 for (
auto& psdu : m_psduMap)
806 psdu.second->SetDuration(durationId);
810 if (timerType == WifiTxTimer::NOT_RUNNING)
815 Simulator::Schedule(txDuration + m_phy->GetSifs(),
816 &HeFrameExchangeManager::SendPsduMap,
819 else if (!m_txParams.m_txVector.IsUlMu())
821 Simulator::Schedule(txDuration, &HeFrameExchangeManager::TransmissionSucceeded,
this);
826 Time timeout = txDuration + m_phy->GetSifs() + m_phy->GetSlot() +
827 WifiPhy::CalculatePhyPreambleAndHeaderDuration(*responseTxVector);
828 m_channelAccessManager->NotifyAckTimeoutStartNow(
timeout);
833 case WifiTxTimer::WAIT_NORMAL_ACK_AFTER_DL_MU_PPDU:
835 m_txTimer.Set(timerType,
837 staExpectResponseFrom,
838 &HeFrameExchangeManager::NormalAckTimeout,
841 m_txParams.m_txVector);
843 case WifiTxTimer::WAIT_BLOCK_ACK:
845 m_txTimer.Set(timerType,
847 staExpectResponseFrom,
848 &HeFrameExchangeManager::BlockAckTimeout,
851 m_txParams.m_txVector);
853 case WifiTxTimer::WAIT_BLOCK_ACKS_IN_TB_PPDU:
854 m_txTimer.Set(timerType,
856 staExpectResponseFrom,
857 &HeFrameExchangeManager::BlockAcksInTbPpduTimeout,
860 staExpectResponseFrom.size());
862 case WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF:
863 case WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF:
864 m_txTimer.Set(timerType,
866 staExpectResponseFrom,
867 &HeFrameExchangeManager::TbPpduTimeout,
870 staExpectResponseFrom.size());
872 case WifiTxTimer::WAIT_BLOCK_ACK_AFTER_TB_PPDU:
873 m_txTimer.Set(timerType,
875 staExpectResponseFrom,
876 &HeFrameExchangeManager::BlockAckAfterTbPpduTimeout,
878 m_psduMap.begin()->second,
879 m_txParams.m_txVector);
888 ForwardPsduMapDown(psduMap, m_txParams.m_txVector);
890 if (timerType == WifiTxTimer::WAIT_BLOCK_ACKS_IN_TB_PPDU ||
891 timerType == WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF ||
892 timerType == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF)
895 auto hePhy = StaticCast<HePhy>(m_phy->GetPhyEntity(responseTxVector->GetModulationClass()));
896 hePhy->SetTrigVector(m_trigVector, m_txTimer.GetDelayLeft());
898 else if (timerType == WifiTxTimer::NOT_RUNNING &&
899 (m_txParams.m_txVector.IsUlMu() ||
900 m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE))
904 Simulator::Schedule(txDuration, &WifiPsduMap::clear, &m_psduMap);
907 if (m_txTimer.IsRunning() && timerType != WifiTxTimer::WAIT_BLOCK_ACK_AFTER_TB_PPDU)
913 for (
const auto& address : staExpectResponseFrom)
915 if (!GetWifiRemoteStationManager()->GetEmlsrEnabled(address) ||
916 timerType == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF ||
917 m_protectedStas.contains(address))
919 m_sentFrameTo.insert(address);
933 auto sigBMode = hePhy->GetSigBMode(txVector);
937 for (
const auto& psdu : psduMap)
939 NS_LOG_DEBUG(
"Transmitting: [STAID=" << psdu.first <<
", " << *psdu.second <<
"]");
942 for (
const auto& [staId, psdu] : psduMap)
944 FinalizeMacHeader(psdu);
945 NotifyTxToEdca(psdu);
949 if (psduMap.size() > 1 || psduMap.begin()->second->IsAggregate() ||
950 psduMap.begin()->second->IsSingle())
955 const auto txDuration = WifiPhy::CalculateTxDuration(psduMap, txVector, m_phy->GetPhyBand());
956 SetTxNav(*psduMap.cbegin()->second->begin(), txDuration);
958 m_phy->Send(psduMap, txVector);
962HeFrameExchangeManager::PrepareMuBar(
const WifiTxVector& responseTxVector,
963 std::map<uint16_t, CtrlBAckRequestHeader> recipients)
const
970 SetTargetRssi(muBar);
976 for (
auto& userInfo : muBar)
978 auto recipientIt = recipients.find(userInfo.GetAid12());
979 NS_ASSERT(recipientIt != recipients.end());
982 userInfo.SetMuBarTriggerDepUserInfo(recipientIt->second);
986 bar->AddHeader(muBar);
994 rxAddress = Mac48Address::GetBroadcast();
999 rxAddress = m_apMac->GetStaList(m_linkId).at(recipients.begin()->first);
1011 return Create<WifiMpdu>(bar, hdr);
1020 if (protection->
method == WifiProtection::MU_RTS_CTS)
1027 GetCtsTxVectorAfterMuRts(muRtsCtsProtection->muRts,
1028 muRtsCtsProtection->muRts.begin()->GetAid12());
1031 muRtsCtsProtection->muRts.GetSerializedSize() + WIFI_MAC_FCS_LENGTH;
1032 muRtsCtsProtection->protectionTime =
1033 WifiPhy::CalculateTxDuration(muRtsSize,
1034 muRtsCtsProtection->muRtsTxVector,
1035 m_phy->GetPhyBand()) +
1036 WifiPhy::CalculateTxDuration(
GetCtsSize(), ctsTxVector, m_phy->GetPhyBand()) +
1037 2 * m_phy->GetSifs();
1041 VhtFrameExchangeManager::CalculateProtectionTime(protection);
1054 if (acknowledgment->
method == WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE)
1061 NS_ABORT_IF(dlMuBarBaAcknowledgment->stationsReplyingWithNormalAck.size() +
1062 dlMuBarBaAcknowledgment->stationsReplyingWithBlockAck.size() >
1065 if (!dlMuBarBaAcknowledgment->stationsReplyingWithNormalAck.empty())
1068 dlMuBarBaAcknowledgment->stationsReplyingWithNormalAck.begin()->second;
1071 WifiPhy::CalculateTxDuration(
GetAckSize(), info.ackTxVector, m_phy->GetPhyBand());
1074 if (!dlMuBarBaAcknowledgment->stationsReplyingWithBlockAck.empty())
1077 dlMuBarBaAcknowledgment->stationsReplyingWithBlockAck.begin()->second;
1079 m_phy->GetSifs() + WifiPhy::CalculateTxDuration(
GetBlockAckSize(info.baType),
1080 info.blockAckTxVector,
1081 m_phy->GetPhyBand());
1084 for (
const auto& stations : dlMuBarBaAcknowledgment->stationsSendBlockAckReqTo)
1086 const auto& info = stations.second;
1087 duration += m_phy->GetSifs() +
1089 info.blockAckReqTxVector,
1090 m_phy->GetPhyBand()) +
1093 info.blockAckTxVector,
1094 m_phy->GetPhyBand());
1097 dlMuBarBaAcknowledgment->acknowledgmentTime = duration;
1102 else if (acknowledgment->
method == WifiAcknowledgment::DL_MU_TF_MU_BAR)
1104 auto dlMuTfMuBarAcknowledgment =
static_cast<WifiDlMuTfMuBar*
>(acknowledgment);
1108 for (
const auto& stations : dlMuTfMuBarAcknowledgment->stationsReplyingWithBlockAck)
1111 const auto& info = stations.second;
1112 NS_ASSERT(info.blockAckTxVector.GetHeMuUserInfoMap().size() == 1);
1113 uint16_t staId = info.blockAckTxVector.GetHeMuUserInfoMap().begin()->first;
1115 info.blockAckTxVector,
1116 m_phy->GetPhyBand(),
1119 if (currBlockAckDuration > duration)
1121 duration = currBlockAckDuration;
1127 WifiTxVector& txVector = dlMuTfMuBarAcknowledgment->stationsReplyingWithBlockAck.begin()
1128 ->second.blockAckTxVector;
1129 std::tie(dlMuTfMuBarAcknowledgment->ulLength, duration) =
1130 HePhy::ConvertHeTbPpduDurationToLSigLength(duration, txVector, m_phy->GetPhyBand());
1133 ? TriggerFrameVariant::HE
1134 : TriggerFrameVariant::EHT;
1137 dlMuTfMuBarAcknowledgment->muBarTxVector.GetChannelWidth(),
1138 dlMuTfMuBarAcknowledgment->barTypes);
1139 if (dlMuTfMuBarAcknowledgment->muBarTxVector.GetModulationClass() >=
WIFI_MOD_CLASS_VHT)
1142 muBarSize = MpduAggregator::GetSizeIfAggregated(muBarSize, 0);
1144 dlMuTfMuBarAcknowledgment->acknowledgmentTime =
1146 WifiPhy::CalculateTxDuration(muBarSize,
1147 dlMuTfMuBarAcknowledgment->muBarTxVector,
1148 m_phy->GetPhyBand()) +
1149 m_phy->GetSifs() + duration;
1154 else if (acknowledgment->
method == WifiAcknowledgment::DL_MU_AGGREGATE_TF)
1160 for (
const auto& stations : dlMuAggrTfAcknowledgment->stationsReplyingWithBlockAck)
1163 const auto& info = stations.second;
1164 NS_ASSERT(info.blockAckTxVector.GetHeMuUserInfoMap().size() == 1);
1165 uint16_t staId = info.blockAckTxVector.GetHeMuUserInfoMap().begin()->first;
1167 info.blockAckTxVector,
1168 m_phy->GetPhyBand(),
1171 if (currBlockAckDuration > duration)
1173 duration = currBlockAckDuration;
1180 dlMuAggrTfAcknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
1181 std::tie(dlMuAggrTfAcknowledgment->ulLength, duration) =
1182 HePhy::ConvertHeTbPpduDurationToLSigLength(duration, txVector, m_phy->GetPhyBand());
1183 dlMuAggrTfAcknowledgment->acknowledgmentTime = m_phy->GetSifs() + duration;
1188 else if (acknowledgment->
method == WifiAcknowledgment::UL_MU_MULTI_STA_BA)
1193 ulMuMultiStaBa->multiStaBaTxVector,
1194 m_phy->GetPhyBand());
1195 ulMuMultiStaBa->acknowledgmentTime = m_phy->GetSifs() + duration;
1200 else if (acknowledgment->
method == WifiAcknowledgment::ACK_AFTER_TB_PPDU)
1209 VhtFrameExchangeManager::CalculateAcknowledgmentTime(acknowledgment);
1214HeFrameExchangeManager::GetCtsModeAfterMuRts()
const
1219 : OfdmPhy::GetOfdmRate6Mbps();
1224 uint16_t staId)
const
1229 NS_ASSERT_MSG(userInfoIt != trigger.
end(),
"User Info field for AID=" << staId <<
" not found");
1232 if (uint8_t ru = userInfoIt->GetMuRtsRuAllocation(); ru < 65)
1254 auto txVector = GetWifiRemoteStationManager()->GetCtsTxVector(m_bssid, GetCtsModeAfterMuRts());
1256 txVector.SetChannelWidth(bw);
1262HeFrameExchangeManager::GetTxDuration(
uint32_t ppduPayloadSize,
1268 return VhtFrameExchangeManager::GetTxDuration(ppduPayloadSize, receiver, txParams);
1275 txParams.
m_acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF)
1279 NS_ASSERT_MSG(psduInfo,
"No information for " << receiver <<
" in TX params");
1280 NS_ASSERT_MSG(!psduInfo->seqNumbers.empty(),
"No sequence number for " << receiver);
1281 const auto tid = psduInfo->seqNumbers.cbegin()->first;
1284 ? TriggerFrameVariant::HE
1285 : TriggerFrameVariant::EHT;
1286 ppduPayloadSize = MpduAggregator::GetSizeIfAggregated(
1289 {m_mac->GetBarTypeAsOriginator(receiver, tid)}),
1293 uint16_t staId = (txParams.
m_txVector.
IsDlMu() ? m_apMac->GetAssociationId(receiver, m_linkId)
1294 : m_staMac->GetAssociationId());
1295 Time psduDuration = WifiPhy::CalculateTxDuration(ppduPayloadSize,
1297 m_phy->GetPhyBand(),
1304HeFrameExchangeManager::TbPpduTimeout(
WifiPsduMap* psduMap, std::size_t nSolicitedStations)
1307 DoTbPpduTimeout(psduMap, nSolicitedStations,
true);
1312 std::size_t nSolicitedStations,
1313 bool updateFailedCw)
1315 const auto& staMissedTbPpduFrom = m_txTimer.GetStasExpectedToRespond();
1316 NS_LOG_FUNCTION(
this << psduMap << staMissedTbPpduFrom.size() << nSolicitedStations
1323 NS_ASSERT(!staMissedTbPpduFrom.empty());
1326 if (staMissedTbPpduFrom.size() == nSolicitedStations)
1330 psduMap->cbegin()->second->GetPayload(0)->PeekHeader(trigger);
1332 if (m_continueTxopAfterBsrpTf && m_edca->GetTxopLimit(m_linkId).IsZero() &&
1335 SendCfEndIfNeeded();
1338 TransmissionFailed(!updateFailedCw);
1340 else if (!m_multiStaBaEvent.IsPending())
1342 m_edca->ResetCw(m_linkId);
1343 TransmissionSucceeded();
1349 for (
const auto& address : staMissedTbPpduFrom)
1351 NS_LOG_DEBUG(address <<
" did not respond, hence it is no longer protected");
1352 m_protectedStas.erase(address);
1353 m_sentFrameTo.erase(address);
1355 if (m_protectedIfResponded)
1357 m_protectedStas.merge(m_sentFrameTo);
1359 m_sentFrameTo.clear();
1367 std::size_t nSolicitedStations)
1372 NS_ASSERT(m_txParams.m_acknowledgment &&
1373 (m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF ||
1374 m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_TF_MU_BAR));
1377 const auto& staMissedBlockAckFrom = m_txTimer.GetStasExpectedToRespond();
1378 NS_ASSERT(!staMissedBlockAckFrom.empty());
1380 if (staMissedBlockAckFrom.size() == nSolicitedStations)
1383 GetWifiRemoteStationManager()->ReportDataFailed(*psduMap->begin()->second->begin());
1389 m_triggerFrame =
nullptr;
1392 for (
const auto& sta : staMissedBlockAckFrom)
1394 auto psdu = GetPsduTo(sta, *psduMap);
1396 MissedBlockAck(psdu, m_txParams.m_txVector);
1401 if (staMissedBlockAckFrom.size() == nSolicitedStations)
1404 TransmissionFailed();
1408 m_edca->ResetCw(m_linkId);
1409 TransmissionSucceeded();
1419 GetWifiRemoteStationManager()->ReportDataFailed(*psdu->begin());
1421 MissedBlockAck(psdu, m_txParams.m_txVector);
1436 VhtFrameExchangeManager::NormalAckTimeout(mpdu, txVector);
1441 for (
auto& psdu : m_psduMap)
1445 if (mpdu->IsQueued())
1447 m_mac->GetTxopQueue(mpdu->GetQueueAc())->GetOriginal(mpdu)->GetHeader().SetRetry();
1448 mpdu->ResetInFlight(m_linkId);
1460 VhtFrameExchangeManager::BlockAckTimeout(psdu, txVector);
1465 for (
auto& psdu : m_psduMap)
1469 if (mpdu->IsQueued())
1471 mpdu->GetHeader().SetRetry();
1487 for (
const auto& userInfoField : trigger)
1490 userInfoField.GetAid12(),
1491 {userInfoField.GetRuAllocation(), userInfoField.GetUlMcs(), userInfoField.GetNss()});
1503 uint16_t staId = m_staMac->GetAssociationId();
1510 NS_ASSERT_MSG(heConfiguration,
"This STA has to be an HE station to send an HE TB PPDU");
1513 if (userInfoIt->IsUlTargetRssiMaxTxPower())
1515 NS_LOG_LOGIC(
"AP requested using the max transmit power (" << m_phy->GetTxPowerEnd()
1521 uint8_t powerLevel = GetWifiRemoteStationManager()->GetDefaultTxPowerLevel();
1539 auto optRssi = GetMostRecentRssi(triggerSender);
1545 auto reqTxPower =
dBm_u{
static_cast<double>(userInfoIt->GetUlTargetRssi() + pathLossDb)};
1548 uint8_t numPowerLevels = m_phy->GetNTxPower();
1549 if (numPowerLevels > 1)
1551 dBm_u step = (m_phy->GetTxPowerEnd() - m_phy->GetTxPowerStart()) / (numPowerLevels - 1);
1552 powerLevel =
static_cast<uint8_t
>(
1553 ceil((reqTxPower - m_phy->GetTxPowerStart()) /
1555 if (powerLevel > numPowerLevels)
1557 powerLevel = numPowerLevels;
1560 if (reqTxPower > m_phy->GetPower(powerLevel))
1562 NS_LOG_WARN(
"The requested power level (" << reqTxPower <<
"dBm) cannot be satisfied (max: "
1563 << m_phy->GetTxPowerEnd() <<
"dBm)");
1567 <<
"{pathLoss=" << pathLossDb <<
"dB, reqTxPower=" << reqTxPower <<
"dBm}"
1569 <<
"{powerLevel=" << +powerLevel <<
" -> " << m_phy->GetPower(powerLevel) <<
"dBm}"
1570 <<
" PHY power capa "
1571 <<
"{min=" << m_phy->GetTxPowerStart() <<
"dBm, max=" << m_phy->GetTxPowerEnd()
1572 <<
"dBm, levels:" << +numPowerLevels <<
"}");
1578HeFrameExchangeManager::GetMostRecentRssi(
const Mac48Address& address)
const
1580 return GetWifiRemoteStationManager()->GetMostRecentRssi(address);
1590 m_phy->GetPower(GetWifiRemoteStationManager()->GetDefaultTxPowerLevel())));
1591 for (
auto& userInfo : trigger)
1593 const auto staList = m_apMac->GetStaList(m_linkId);
1594 auto itAidAddr = staList.find(userInfo.GetAid12());
1596 auto optRssi = GetMostRecentRssi(itAidAddr->second);
1598 auto rssi =
static_cast<int8_t>(*optRssi);
1599 rssi = (rssi >= -20)
1601 : ((rssi <= -110) ? -110 : rssi);
1602 userInfo.SetUlTargetRssi(rssi);
1611 auto txVectorCopy = txVector;
1613 if (psdu->GetNMpdus() == 1 && psdu->GetHeader(0).IsTrigger())
1616 psdu->GetPayload(0)->PeekHeader(trigger);
1630 if (m_staMac !=
nullptr && m_staMac->IsAssociated() &&
1641 psdu = Create<const WifiPsdu>(Create<Packet>(), rts);
1645 GetWifiRemoteStationManager()->GetCtsTxVector(m_bssid, GetCtsModeAfterMuRts());
1648 VhtFrameExchangeManager::PostProcessFrame(psdu, txVectorCopy);
1658 if (!UlMuCsMediumIdle(trigger))
1660 NS_LOG_DEBUG(
"UL MU CS indicated medium busy, cannot send CTS");
1664 NS_ASSERT(m_staMac !=
nullptr && m_staMac->IsAssociated());
1665 WifiTxVector ctsTxVector = GetCtsTxVectorAfterMuRts(trigger, m_staMac->GetAssociationId());
1668 DoSendCtsAfterRts(muRtsHdr, ctsTxVector, muRtsSnr);
1678 txParams.
m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
1681 NS_ASSERT(!acknowledgment->stationsReceivingMultiStaBa.empty());
1684 blockAck.
SetType(acknowledgment->baType);
1688 for (
const auto& staInfo : acknowledgment->stationsReceivingMultiStaBa)
1690 receiver = staInfo.first.first;
1691 uint8_t tid = staInfo.first.second;
1692 std::size_t index = staInfo.second;
1694 blockAck.
SetAid11(m_apMac->GetAssociationId(receiver, m_linkId), index);
1700 NS_LOG_DEBUG(
"Multi-STA Block Ack: Sending All-ack to=" << receiver);
1705 if (acknowledgment->baType.m_bitmapLen.at(index) == 0)
1708 NS_LOG_DEBUG(
"Multi-STA Block Ack: Sending Ack to=" << receiver);
1716 auto agreement = m_mac->GetBaAgreementEstablishedAsRecipient(receiver, tid);
1718 agreement->get().FillBlockAckBitmap(blockAck, index);
1719 NS_LOG_DEBUG(
"Multi-STA Block Ack: Sending Block Ack with seq="
1721 <<
" tid=" << +tid);
1727 hdr.
SetAddr1(acknowledgment->stationsReceivingMultiStaBa.size() == 1
1729 : Mac48Address::GetBroadcast());
1735 packet->AddHeader(blockAck);
1737 GetWifiPsdu(Create<WifiMpdu>(packet, hdr), acknowledgment->multiStaBaTxVector);
1740 acknowledgment->multiStaBaTxVector,
1741 m_phy->GetPhyBand());
1753 const auto singleDurationId =
Max(durationId - m_phy->GetSifs() - txDuration,
Seconds(0));
1754 if (m_edca->GetTxopLimit(m_linkId).IsZero())
1756 psdu->SetDuration(singleDurationId);
1760 auto duration =
Max(m_edca->GetRemainingTxop(m_linkId) - txDuration,
Seconds(0));
1761 if (m_protectSingleExchange)
1763 duration = std::min(duration, singleDurationId + m_singleExchangeProtectionSurplus);
1765 psdu->SetDuration(duration);
1768 psdu->GetPayload(0)->AddPacketTag(m_muSnrTag);
1770 ForwardPsduDown(psdu, acknowledgment->multiStaBaTxVector);
1774 m_edca->ResetCw(m_linkId);
1776 Simulator::Schedule(txDuration, &HeFrameExchangeManager::TransmissionSucceeded,
this);
1785 NS_ASSERT(m_staMac && m_staMac->IsAssociated());
1787 NS_LOG_DEBUG(
"Received a Trigger Frame (basic variant) soliciting a transmission");
1789 if (!UlMuCsMediumIdle(trigger))
1800 std::vector<uint8_t> tids;
1801 uint16_t staId = m_staMac->GetAssociationId();
1804 for (uint8_t i = 0; i < 4; i++)
1807 tids.push_back(acIt->second.GetHighTid());
1808 tids.push_back(acIt->second.GetLowTid());
1820 Time ppduDuration = HePhy::ConvertLSigLengthToHeTbPpduDuration(trigger.
GetUlLength(),
1822 m_phy->GetPhyBand());
1824 for (
const auto& tid : tids)
1828 if (!m_mac->GetBaAgreementEstablishedAsOriginator(hdr.
GetAddr2(), tid))
1838 if (
auto mpdu = GetBar(edca->GetAccessCategory(), tid, hdr.
GetAddr2());
1839 mpdu && TryAddMpdu(mpdu, txParams, ppduDuration))
1842 psdu = Create<WifiPsdu>(mpdu,
true);
1848 GetWifiRemoteStationManager()->GetMldAddress(hdr.
GetAddr2()).value_or(hdr.
GetAddr2());
1849 if (
auto mpdu = edca->PeekNextMpdu(m_linkId, tid, receiver))
1851 mpdu = CreateAliasIfNeeded(mpdu);
1852 if (
auto item = edca->GetNextMpdu(m_linkId, mpdu, txParams, ppduDuration,
false))
1855 std::vector<Ptr<WifiMpdu>> mpduList =
1856 m_mpduAggregator->GetNextAmpdu(item, txParams, ppduDuration);
1857 psdu = (mpduList.size() > 1 ? Create<WifiPsdu>(std::move(mpduList))
1858 : Create<WifiPsdu>(item,
true));
1866 psdu->SetDuration(hdr.
GetDuration() - m_phy->GetSifs() - ppduDuration);
1867 SendPsduMapWithProtection(
WifiPsduMap{{staId, psdu}}, txParams);
1872 SendQosNullFramesInTbPpdu(trigger, hdr);
1882 NS_ASSERT(m_staMac && m_staMac->IsAssociated());
1886 if (!UlMuCsMediumIdle(trigger))
1892 GetWifiRemoteStationManager()->GetMldAddress(hdr.
GetAddr2()).value_or(hdr.
GetAddr2());
1895 header.
SetAddr2(m_mac->GetAddress());
1910 Time ppduDuration = HePhy::ConvertLSigLengthToHeTbPpduDuration(trigger.
GetUlLength(),
1912 m_phy->GetPhyBand());
1915 std::vector<Ptr<WifiMpdu>> mpduList;
1917 for (uint8_t tid = 0; tid < 8; ++tid)
1919 if (!m_mac->GetBaAgreementEstablishedAsOriginator(hdr.
GetAddr2(), tid))
1921 NS_LOG_DEBUG(
"Skipping tid=" << +tid <<
" because no agreement established");
1931 auto mpdu = Create<WifiMpdu>(Create<Packet>(), header);
1932 mpdu = CreateAliasIfNeeded(mpdu);
1934 UpdateTxDuration(header.
GetAddr1(), txParams);
1945 NS_LOG_DEBUG(
"Aggregating a QoS Null frame with tid=" << +tid);
1947 mpduList.push_back(mpdu);
1950 if (mpduList.empty())
1952 NS_LOG_DEBUG(
"Not enough time to send a QoS Null frame");
1956 Ptr<WifiPsdu> psdu = (mpduList.size() > 1 ? Create<WifiPsdu>(std::move(mpduList))
1957 : Create<WifiPsdu>(mpduList.front(),
true));
1958 uint16_t staId = m_staMac->GetAssociationId();
1959 SendPsduMapWithProtection(
WifiPsduMap{{staId, psdu}}, txParams);
1970 auto agreement = m_mac->GetBaAgreementEstablishedAsRecipient(m_bssid, tid);
1974 NS_LOG_DEBUG(
"There's not a valid agreement for this BlockAckReq");
1978 if (!UlMuCsMediumIdle(trigger))
1984 auto txVector = GetHeTbTxVector(trigger, m_bssid);
1985 SendBlockAck(*agreement, durationId, txVector, snr);
2004 if (ra == m_bssid || ta == m_bssid || bssid == m_bssid)
2012 if (hdr.
IsCtl() && ta == empty && ra == m_txopHolder)
2026 if (bssid != empty && bssid != m_bssid)
2034 if (bssid == empty && ta != empty && ra != empty && ta != m_bssid && ra != m_bssid)
2047 const auto bssColor = m_mac->GetHeConfiguration()->m_bssColor;
2050 return bssColor != 0 && bssColor == txVector.
GetBssColor();
2056 const Time& surplus)
2075 if (!IsIntraBssPpdu(hdr, txVector))
2077 NS_LOG_DEBUG(
"PPDU not classified as intra-BSS, update the basic NAV");
2078 VhtFrameExchangeManager::UpdateNav(hdr, txVector, surplus);
2082 NS_LOG_DEBUG(
"PPDU classified as intra-BSS, update the intra-BSS NAV");
2085 duration += surplus;
2093 NS_LOG_DEBUG(
"Received CF-End, resetting the intra-BSS NAV");
2094 IntraBssNavResetTimeout();
2100 auto intraBssNavEnd = Simulator::Now() + duration;
2101 if (intraBssNavEnd > m_intraBssNavEnd)
2103 m_intraBssNavEnd = intraBssNavEnd;
2104 NS_LOG_DEBUG(
"Updated intra-BSS NAV=" << m_intraBssNavEnd);
2119 GetWifiRemoteStationManager()->GetCtsTxVector(addr2, txVector.
GetMode());
2120 auto navResetDelay =
2121 2 * m_phy->GetSifs() +
2122 WifiPhy::CalculateTxDuration(
GetCtsSize(), ctsTxVector, m_phy->GetPhyBand()) +
2123 WifiPhy::CalculatePhyPreambleAndHeaderDuration(ctsTxVector) + 2 * m_phy->GetSlot();
2124 m_intraBssNavResetEvent.Cancel();
2125 m_intraBssNavResetEvent =
2126 Simulator::Schedule(navResetDelay,
2127 &HeFrameExchangeManager::IntraBssNavResetTimeout,
2131 NS_LOG_DEBUG(
"Current intra-BSS NAV=" << m_intraBssNavEnd);
2133 m_channelAccessManager->NotifyNavStartNow(duration);
2137HeFrameExchangeManager::ClearTxopHolderIfNeeded()
2140 if (m_intraBssNavEnd <= Simulator::Now())
2142 m_txopHolder.reset();
2147HeFrameExchangeManager::NavResetTimeout()
2150 m_navEnd = Simulator::Now();
2153 Time intraBssNav = Simulator::GetDelayLeft(m_intraBssNavResetEvent);
2154 m_channelAccessManager->NotifyNavResetNow(intraBssNav);
2158HeFrameExchangeManager::IntraBssNavResetTimeout()
2161 m_intraBssNavEnd = Simulator::Now();
2162 ClearTxopHolderIfNeeded();
2164 Time basicNav = Simulator::GetDelayLeft(m_navResetEvent);
2165 m_channelAccessManager->NotifyNavResetNow(basicNav);
2168std::optional<Mac48Address>
2179 return VhtFrameExchangeManager::FindTxopHolder(hdr, txVector);
2181 return std::nullopt;
2185HeFrameExchangeManager::VirtualCsMediumIdle()
const
2190 return m_navEnd <= Simulator::Now() && m_intraBssNavEnd <= Simulator::Now();
2206 const Time now = Simulator::Now();
2213 NS_ASSERT_MSG(m_staMac,
"UL MU CS is only performed by non-AP STAs");
2216 "No User Info field for STA (" << m_self
2217 <<
") AID=" << m_staMac->GetAssociationId());
2219 std::set<uint8_t> indices;
2223 auto ctsTxVector = GetCtsTxVectorAfterMuRts(trigger, m_staMac->GetAssociationId());
2224 auto bw = ctsTxVector.GetChannelWidth();
2225 indices = m_phy->GetOperatingChannel().GetAll20MHzChannelIndicesInPrimary(bw);
2230 m_phy->GetOperatingChannel().Get20MHzIndicesCoveringRu(userInfoIt->GetRuAllocation(),
2233 return !m_channelAccessManager->GetPer20MHzBusy(indices);
2242 NS_LOG_FUNCTION(
this << *mpdu << rxSignalInfo << txVector << inAmpdu);
2245 NS_ASSERT(mpdu->GetHeader().GetAddr1().IsGroup() || mpdu->GetHeader().GetAddr1() == m_self);
2249 if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
2250 m_txTimer.GetReason() == WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF)
2253 NS_ASSERT(m_txParams.m_acknowledgment &&
2254 m_txParams.m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
2255 auto acknowledgment =
static_cast<WifiUlMuMultiStaBa*
>(m_txParams.m_acknowledgment.get());
2258 if (!m_txTimer.GetStasExpectedToRespond().contains(sender))
2260 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2266 NS_LOG_DEBUG(
"Received a BlockAckReq in a TB PPDU from " << sender);
2269 mpdu->GetPacket()->PeekHeader(blockAckReq);
2272 GetBaManager(tid)->NotifyGotBlockAckRequest(
2273 m_mac->GetMldAddress(sender).value_or(sender),
2278 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, tid), index);
2279 acknowledgment->baType.m_bitmapLen.push_back(
2280 m_mac->GetBaTypeAsRecipient(sender, tid).m_bitmapLen.at(0));
2282 m_muSnrTag.Set(staId, rxSignalInfo.
snr);
2286 NS_LOG_DEBUG(
"Received an S-MPDU in a TB PPDU from " << sender <<
" (" << *mpdu <<
")");
2289 GetBaManager(tid)->NotifyGotMpdu(mpdu);
2292 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, tid), index);
2293 acknowledgment->baType.m_bitmapLen.push_back(0);
2295 m_muSnrTag.Set(staId, rxSignalInfo.
snr);
2304 VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
2309 if (!acknowledgment->stationsReceivingMultiStaBa.empty() && !m_multiStaBaEvent.IsPending())
2311 m_multiStaBaEvent = Simulator::Schedule(m_phy->GetSifs(),
2312 &HeFrameExchangeManager::SendMultiStaBlockAck,
2314 std::cref(m_txParams),
2315 mpdu->GetHeader().GetDuration());
2319 m_txTimer.GotResponseFrom(sender);
2321 if (m_txTimer.GetStasExpectedToRespond().empty())
2325 m_channelAccessManager->NotifyAckTimeoutResetNow();
2327 if (!m_multiStaBaEvent.IsPending())
2332 m_edca->ResetCw(m_linkId);
2333 TransmissionSucceeded();
2341 if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
2342 m_txTimer.GetReason() == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF &&
2345 const auto& sender = hdr.
GetAddr2();
2347 if (!m_txTimer.GetStasExpectedToRespond().contains(sender))
2349 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2354 NS_LOG_WARN(
"No QoS Null frame in the received MPDU");
2358 NS_LOG_DEBUG(
"Received a QoS Null frame in a TB PPDU from " << sender);
2359 ReceivedQosNullAfterBsrpTf(sender);
2367 if (hdr.
IsCts() && m_txTimer.IsRunning() &&
2368 m_txTimer.GetReason() == WifiTxTimer::WAIT_CTS && m_psduMap.size() == 1)
2373 Mac48Address sender = m_psduMap.begin()->second->GetAddr1();
2377 mpdu->GetPacket()->PeekPacketTag(tag);
2378 GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
2379 GetWifiRemoteStationManager()->ReportRtsOk(m_psduMap.begin()->second->GetHeader(0),
2385 m_channelAccessManager->NotifyCtsTimeoutResetNow();
2386 ProtectionCompleted();
2388 else if (hdr.
IsCts() && m_txTimer.IsRunning() &&
2389 m_txTimer.GetReason() == WifiTxTimer::WAIT_CTS_AFTER_MU_RTS)
2394 NS_LOG_DEBUG(
"Received a CTS frame in response to an MU-RTS");
2397 m_channelAccessManager->NotifyCtsTimeoutResetNow();
2398 ProtectionCompleted();
2400 else if (hdr.
IsAck() && m_txTimer.IsRunning() &&
2401 m_txTimer.GetReason() == WifiTxTimer::WAIT_NORMAL_ACK_AFTER_DL_MU_PPDU)
2405 NS_ASSERT(m_txParams.m_acknowledgment->method ==
2406 WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE);
2408 auto acknowledgment =
2410 NS_ASSERT(acknowledgment->stationsReplyingWithNormalAck.size() == 1);
2412 uint16_t staId = m_apMac->GetAssociationId(
2413 acknowledgment->stationsReplyingWithNormalAck.begin()->first,
2415 auto it = m_psduMap.find(staId);
2418 acknowledgment->stationsReplyingWithNormalAck.begin()->first);
2420 mpdu->GetPacket()->PeekPacketTag(tag);
2421 ReceivedNormalAck(*it->second->begin(),
2422 m_txParams.m_txVector,
2435 m_txTimer.GetReason() == WifiTxTimer::WAIT_BLOCK_ACKS_IN_TB_PPDU)
2438 NS_LOG_DEBUG(
"Received BlockAck in TB PPDU from=" << sender);
2441 mpdu->GetPacket()->PeekPacketTag(tag);
2445 mpdu->GetPacket()->PeekHeader(blockAck);
2447 std::pair<uint16_t, uint16_t> ret =
2448 GetBaManager(tid)->NotifyGotBlockAck(m_linkId,
2450 m_mac->GetMldAddress(sender).value_or(sender),
2452 GetWifiRemoteStationManager()->ReportAmpduTxStatus(sender,
2457 m_txParams.m_txVector);
2460 if (!m_txTimer.GetStasExpectedToRespond().contains(sender))
2462 NS_LOG_WARN(
"Received a BlockAck from an unexpected stations: " << sender);
2466 m_txTimer.GotResponseFrom(sender);
2468 if (m_txTimer.GetStasExpectedToRespond().empty())
2472 m_channelAccessManager->NotifyAckTimeoutResetNow();
2476 m_triggerFrame =
nullptr;
2479 m_edca->ResetCw(m_linkId);
2481 TransmissionSucceeded();
2484 else if (hdr.
IsBlockAck() && m_txTimer.IsRunning() &&
2485 m_txTimer.GetReason() == WifiTxTimer::WAIT_BLOCK_ACK_AFTER_TB_PPDU)
2488 mpdu->GetPacket()->PeekHeader(blockAck);
2491 "A Multi-STA BlockAck is expected after a TB PPDU");
2493 m_txTimer.GotResponseFrom(hdr.
GetAddr2());
2495 NS_ASSERT(m_staMac && m_staMac->IsAssociated());
2498 NS_LOG_DEBUG(
"The sender is not the AP we are associated with");
2502 uint16_t staId = m_staMac->GetAssociationId();
2505 if (indices.empty())
2507 NS_LOG_DEBUG(
"No Per AID TID Info subfield intended for me");
2512 mpdu->GetPacket()->PeekPacketTag(tag);
2515 for (
const auto& index : indices)
2522 NS_ABORT_IF(m_psduMap.empty() || m_psduMap.begin()->first != staId);
2523 GetBaManager(tid)->NotifyGotAck(m_linkId, *m_psduMap.at(staId)->begin());
2532 NS_ABORT_IF(m_psduMap.empty() || m_psduMap.begin()->first != staId);
2533 std::set<uint8_t> tids = m_psduMap.at(staId)->GetTids();
2534 NS_ABORT_MSG_IF(tids.size() > 1,
"Multi-TID A-MPDUs not supported yet");
2535 tid = *tids.begin();
2538 std::pair<uint16_t, uint16_t> ret = GetBaManager(tid)->NotifyGotBlockAck(
2544 GetWifiRemoteStationManager()->ReportAmpduTxStatus(hdr.
GetAddr2(),
2549 m_txParams.m_txVector);
2552 if (m_psduMap.at(staId)->GetHeader(0).IsQosData() &&
2554 || std::any_of(blockAck.
GetBitmap(index).begin(),
2556 [](uint8_t b) { return b != 0; })))
2558 NS_ASSERT(m_psduMap.at(staId)->GetHeader(0).HasData());
2559 NS_ASSERT(m_psduMap.at(staId)->GetHeader(0).GetQosTid() == tid);
2564 m_mac->GetQosTxop(tid)->StartMuEdcaTimerNow(m_linkId);
2570 m_channelAccessManager->NotifyAckTimeoutResetNow();
2572 for (
const auto& [staId, psdu] : m_psduMap)
2574 if (psdu->GetNMpdus() == 1 && psdu->GetHeader(0).IsBlockAckReq())
2581 else if (hdr.
IsBlockAck() && m_txTimer.IsRunning() &&
2582 m_txTimer.GetReason() == WifiTxTimer::WAIT_BLOCK_ACK)
2588 VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
2601 m_triggerFrameInAmpdu =
true;
2606 mpdu->GetPacket()->PeekHeader(trigger);
2617 uint16_t staId = m_staMac->GetAssociationId();
2622 NS_LOG_DEBUG(
"Received MU-RTS Trigger Frame from=" << sender);
2623 GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
2633 m_sendCtsEvent = Simulator::Schedule(m_phy->GetSifs(),
2634 &HeFrameExchangeManager::SendCtsAfterMuRts,
2643 NS_LOG_DEBUG(
"Received MU-BAR Trigger Frame from=" << sender);
2644 GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
2652 GetBaManager(tid)->NotifyGotBlockAckRequest(
2653 m_mac->GetMldAddress(sender).value_or(sender),
2657 Simulator::Schedule(m_phy->GetSifs(),
2658 &HeFrameExchangeManager::ReceiveMuBarTrigger,
2667 Simulator::Schedule(m_phy->GetSifs(),
2668 &HeFrameExchangeManager::ReceiveBasicTrigger,
2673 else if (trigger.
IsBsrp())
2675 Simulator::Schedule(m_phy->GetSifs(),
2676 &HeFrameExchangeManager::SendQosNullFramesInTbPpdu,
2685 VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
2693 VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
2701 const std::vector<bool>& perMpduStatus)
2703 std::set<uint8_t> tids = psdu->GetTids();
2705 if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
2706 m_txTimer.GetReason() == WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF)
2709 NS_ASSERT(m_txParams.m_acknowledgment &&
2710 m_txParams.m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
2711 auto acknowledgment =
static_cast<WifiUlMuMultiStaBa*
>(m_txParams.m_acknowledgment.get());
2714 if (!m_txTimer.GetStasExpectedToRespond().contains(sender))
2716 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2720 NS_LOG_DEBUG(
"Received an A-MPDU in a TB PPDU from " << sender <<
" (" << *psdu <<
")");
2722 if (std::any_of(tids.begin(), tids.end(), [&psdu](uint8_t tid) {
2723 return psdu->GetAckPolicyForTid(tid) == WifiMacHeader::NORMAL_ACK;
2726 if (std::all_of(perMpduStatus.cbegin(), perMpduStatus.cend(), [](
bool v) { return v; }))
2729 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, 14),
2731 acknowledgment->baType.m_bitmapLen.push_back(0);
2737 for (
const auto& tid : tids)
2739 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, tid),
2741 acknowledgment->baType.m_bitmapLen.push_back(
2742 m_mac->GetBaTypeAsRecipient(sender, tid).m_bitmapLen.at(0));
2746 m_muSnrTag.Set(staId, rxSignalInfo.
snr);
2750 if (!acknowledgment->stationsReceivingMultiStaBa.empty() && !m_multiStaBaEvent.IsPending())
2752 m_multiStaBaEvent = Simulator::Schedule(m_phy->GetSifs(),
2753 &HeFrameExchangeManager::SendMultiStaBlockAck,
2755 std::cref(m_txParams),
2756 psdu->GetDuration());
2760 m_txTimer.GotResponseFrom(sender);
2762 if (m_txTimer.GetStasExpectedToRespond().empty())
2766 m_channelAccessManager->NotifyAckTimeoutResetNow();
2768 if (!m_multiStaBaEvent.IsPending())
2773 m_edca->ResetCw(m_linkId);
2774 TransmissionSucceeded();
2782 if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
2783 m_txTimer.GetReason() == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF)
2787 if (!m_txTimer.GetStasExpectedToRespond().contains(sender))
2789 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2792 if (std::none_of(psdu->begin(), psdu->end(), [](
Ptr<WifiMpdu> mpdu) {
2793 return mpdu->GetHeader().IsQosData() && !mpdu->GetHeader().HasData();
2796 NS_LOG_WARN(
"No QoS Null frame in the received PSDU");
2800 NS_LOG_DEBUG(
"Received QoS Null frames in a TB PPDU from " << sender);
2801 ReceivedQosNullAfterBsrpTf(sender);
2807 if (m_triggerFrameInAmpdu)
2810 auto psduIt = psdu->begin();
2811 while (psduIt != psdu->end())
2813 if ((*psduIt)->GetHeader().IsTrigger())
2815 ReceiveMpdu(*psduIt, rxSignalInfo, txVector,
false);
2820 m_triggerFrameInAmpdu =
false;
2825 VhtFrameExchangeManager::EndReceiveAmpdu(psdu, rxSignalInfo, txVector, perMpduStatus);
2834 m_txTimer.GetReason() == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF);
2837 m_txTimer.GotResponseFrom(sender);
2839 if (m_txTimer.GetStasExpectedToRespond().empty())
2842 m_channelAccessManager->NotifyAckTimeoutResetNow();
2846 m_edca->ResetCw(m_linkId);
2847 TransmissionSucceeded();
AttributeValue implementation for Boolean.
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
bool IsPending() const
This method is syntactic sugar for !IsExpired().
std::set< Mac48Address > m_sentRtsTo
the STA(s) which we sent an RTS to (waiting for CTS)
uint8_t m_linkId
the ID of the link this object is associated with
Ptr< WifiMac > m_mac
the MAC layer on this station
bool m_protectedIfResponded
whether a STA is assumed to be protected if replied to a frame requiring acknowledgment
virtual void Reset()
Reset this frame exchange manager.
Mac48Address m_self
the MAC address of this device
virtual void StartProtection(const WifiTxParameters &txParams)
Start the protection mechanism indicated by the given TX parameters.
WifiTxTimer m_txTimer
the timer set upon frame transmission
std::set< Mac48Address > m_protectedStas
STAs that have replied to an RTS in this TXOP.
virtual Time GetRtsDurationId(const WifiTxVector &rtsTxVector, Time txDuration, Time response) const
Compute how to set the Duration/ID field of an RTS frame to send to protect a frame transmitted with ...
virtual void ProtectionCompleted()
Transmit prepared frame immediately, if no protection was used, or in a SIFS, if protection was compl...
virtual void NotifyChannelReleased(Ptr< Txop > txop)
Notify the given Txop that channel has been released.
virtual void CtsTimeout(Ptr< WifiMpdu > rts, const WifiTxVector &txVector)
Called when the CTS timeout expires.
void DoCtsTimeout(const WifiPsduMap &psduMap)
Take required actions when the CTS timer fired after sending an (MU-)RTS to protect the given PSDU ma...
Time m_txNav
the TXNAV timer
virtual void TransmissionSucceeded()
Take necessary actions upon a transmission success.
Ptr< WifiPhy > m_phy
the PHY layer on this station
std::set< Mac48Address > m_sentFrameTo
the STA(s) to which we sent a frame requesting a response
Ptr< ApWifiMac > m_apMac
AP MAC layer pointer (null if not an AP)
Ptr< ChannelAccessManager > m_channelAccessManager
the channel access manager
MHz_u m_allowedWidth
the allowed width for the current transmission
Ptr< StaWifiMac > m_staMac
STA MAC layer pointer (null if not a STA)
virtual void RxStartIndication(WifiTxVector txVector, Time psduDuration)
virtual Time GetMuRtsDurationId(uint32_t muRtsSize, const WifiTxVector &muRtsTxVector, Time txDuration, Time response) const
Compute how to set the Duration/ID field of an MU-RTS Trigger Frame to send to protect a frame transm...
void DoDispose() override
Destructor implementation.
void Reset() override
Reset this frame exchange manager.
WifiMode GetCtsModeAfterMuRts() const
virtual void SendMuRts(const WifiTxParameters &txParams)
Send an MU-RTS to begin an MU-RTS/CTS frame exchange protecting an MU PPDU.
WifiTxParameters m_txParams
the TX parameters for the current PPDU
void RxStartIndication(WifiTxVector txVector, Time psduDuration) override
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.
WifiTxVector GetCtsTxVectorAfterMuRts(const CtrlTriggerHeader &trigger, uint16_t staId) const
Get the TXVECTOR that the station having the given station ID has to use to send a CTS frame after re...
bool m_continueTxopAfterBsrpTf
whether to continue a TXOP a SIFS after the reception of responses to a BSRP TF when TXOP limit is ze...
Ptr< MultiUserScheduler > m_muScheduler
Multi-user Scheduler (HE APs only)
virtual void CtsAfterMuRtsTimeout(Ptr< WifiMpdu > muRts, const WifiTxVector &txVector)
Called when no CTS frame is received after an MU-RTS.
void ProtectionCompleted() override
Transmit prepared frame immediately, if no protection was used, or in a SIFS, if protection was compl...
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,...
void CtsTimeout(Ptr< WifiMpdu > rts, const WifiTxVector &txVector) override
Called when the CTS timeout expires.
EventId m_intraBssNavResetEvent
the event to reset the intra-BSS NAV after an RTS
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 SendPsduMap()
Send the current PSDU map as a DL MU PPDU.
WifiPsduMap m_psduMap
the A-MPDU being transmitted
static TypeId GetTypeId()
Get the type ID.
Time m_intraBssNavEnd
intra-BSS NAV expiration time
std::set< Mac48Address > GetTfRecipients(const CtrlTriggerHeader &trigger) const
Get the (link) address of the non-AP stations solicited by the given Trigger Frame.
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.
void StartProtection(const WifiTxParameters &txParams) override
Start the protection mechanism indicated by the given TX parameters.
~HeFrameExchangeManager() override
void TransmissionSucceeded() override
Take necessary actions upon a transmission success.
static Time ConvertLSigLengthToHeTbPpduDuration(uint16_t length, const WifiTxVector &txVector, WifiPhyBand band)
Ptr< WifiMpdu > GetBar(AcIndex ac, std::optional< uint8_t > optTid=std::nullopt, std::optional< Mac48Address > optAddress=std::nullopt)
Get the next BlockAckRequest or MU-BAR Trigger Frame to send, if any.
void ForwardMpduDown(Ptr< WifiMpdu > mpdu, WifiTxVector &txVector) override
Forward an MPDU down to the PHY layer.
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...
static Mac48Address GetBroadcast()
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.
virtual void DoDispose()
Destructor implementation.
Smart pointer class similar to boost::intrusive_ptr.
Ptr< QosTxop > m_edca
the EDCAF that gained channel access
virtual bool SendCfEndIfNeeded()
Send a CF-End frame to indicate the completion of the TXOP, provided that the remaining duration is l...
Time m_singleExchangeProtectionSurplus
additional time to protect beyond end of the immediate frame exchange in case of non-zero TXOP limit ...
bool m_protectSingleExchange
true if the Duration/ID field in frames establishing protection only covers the immediate frame excha...
virtual Time GetRemainingTxop(uint8_t linkId) const
Return the remaining duration in the current TXOP on the given link.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
static Time Now()
Return the current simulation virtual time.
Introspection did not find any typical Config paths.
double Get() const
Return the SNR value.
Simulation virtual time values and global simulation resolution.
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
bool IsStrictlyPositive() const
Exactly equivalent to t > 0.
bool IsZero() const
Exactly equivalent to t == 0.
Time GetTxopLimit() const
Return the TXOP limit.
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< WifiMpdu > mpdu, const WifiTxVector &txVector) const override
Get a PSDU containing the given MPDU.
static void SetQosAckPolicy(Ptr< WifiMpdu > item, const WifiAcknowledgment *acknowledgment)
Set the QoS Ack policy for the given MPDU, which must be a QoS data frame.
represent a single transmission mode
Time GetSlot() const
Return the slot duration for this PHY.
Time GetSifs() const
Return the Short Interframe Space (SIFS) for this PHY.
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
WifiPhyBand GetPhyBand() const
Get the configured Wi-Fi band.
static Time CalculatePhyPreambleAndHeaderDuration(const WifiTxVector &txVector)
This class stores the TX parameters (TX vector, protection mechanism, acknowledgment mechanism,...
std::optional< Time > m_txDuration
TX duration of the frame.
std::unique_ptr< WifiProtection > m_protection
protection method
uint32_t GetSize(Mac48Address receiver) const
Get the size in bytes of the (A-)MPDU addressed to the given receiver.
std::unique_ptr< WifiAcknowledgment > m_acknowledgment
acknowledgment method
const PsduInfo * GetPsduInfo(Mac48Address receiver) const
Get a pointer to the information about the PSDU addressed to the given receiver, if present,...
void UndoAddMpdu()
Undo the addition of the last MPDU added by calling AddMpdu().
WifiTxVector m_txVector
TXVECTOR of the frame being prepared.
void AddMpdu(Ptr< const WifiMpdu > mpdu)
Record that an MPDU is being added to the current frame.
void Clear()
Reset the TX parameters.
bool IsRunning() const
Return true if the timer is running.
Reason
The reason why the timer was started.
@ WAIT_QOS_NULL_AFTER_BSRP_TF
const std::set< Mac48Address > & GetStasExpectedToRespond() const
void Set(Reason reason, const Time &delay, const std::set< Mac48Address > &from, MEM mem_ptr, OBJ obj, Args... args)
This method is called when a frame soliciting a response is transmitted.
Reason GetReason() const
Get the reason why the timer was started.
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
void SetTxPowerLevel(uint8_t powerlevel)
Sets the selected transmission power level.
uint8_t GetBssColor() const
Get the BSS color.
void SetGuardInterval(Time guardInterval)
Sets the guard interval duration (in nanoseconds)
void SetTriggerResponding(bool triggerResponding)
Set the Trigger Responding parameter to the given value.
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.
WifiPreamble GetPreambleType() const
void SetAggregation(bool aggregation)
Sets if PSDU contains A-MPDU.
void SetChannelWidth(MHz_u channelWidth)
Sets the selected channelWidth.
const HeMuUserInfoMap & GetHeMuUserInfoMap() const
Get a const reference to the map HE MU user-specific transmission information indexed by STA-ID.
WifiModulationClass GetModulationClass() const
Get the modulation class specified by this TXVECTOR.
void SetLength(uint16_t length)
Set the LENGTH field of the L-SIG.
MHz_u GetChannelWidth() const
void SetSigBMode(const WifiMode &mode)
Set the MCS used for SIG-B.
void SetBssColor(uint8_t color)
Set the BSS color.
void SetMode(WifiMode mode)
Sets the selected payload transmission mode.
void SetPreambleType(WifiPreamble preamble)
Sets the preamble type.
#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...
Ptr< const AttributeChecker > MakeBooleanChecker()
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
#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_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
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_PHY_BAND_2_4GHZ
The 2.4 GHz band.
@ 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.
uint32_t GetMuBarSize(TriggerFrameVariant variant, MHz_u bw, const std::list< BlockAckReqType > &types)
Return the total MU-BAR size (including FCS trailer).
U * PeekPointer(const Ptr< U > &p)
bool IsTrigger(const WifiPsduMap &psduMap)
std::unordered_map< uint16_t, Ptr< WifiPsdu > > WifiPsduMap
Map of PSDUs indexed by STA-ID.
uint32_t GetBlockAckRequestSize(BlockAckReqType type)
Return the total BlockAckRequest 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).
bool IsDlMu(WifiPreamble preamble)
Return true if a preamble corresponds to a downlink multi-user transmission.
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
uint32_t GetAckSize()
Return the total Ack size (including FCS trailer).
static constexpr uint16_t SU_STA_ID
STA_ID to identify a single user (SU)
uint32_t GetCtsSize()
Return the total CTS size (including FCS trailer).
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.
const Method method
acknowledgment method
std::optional< Time > acknowledgmentTime
time required by the acknowledgment method
WifiDlMuAggregateTf specifies that a DL MU PPDU made of PSDUs including each a MU-BAR Trigger Frame i...
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...
WifiDlMuTfMuBar specifies that a DL MU PPDU is followed after a SIFS duration by a MU-BAR Trigger Fra...
WifiMuRtsCtsProtection specifies that MU-RTS/CTS protection method is used.
WifiNoAck specifies that no acknowledgment is required.
WifiNoProtection specifies that no protection method is used.
WifiProtection is an abstract base struct.
const Method method
protection method
WifiUlMuMultiStaBa specifies that a Basic Trigger Frame is being sent to solicit TB PPDUs that will b...
BlockAckType baType
BlockAck type.
std::map< std::pair< Mac48Address, uint8_t >, std::size_t > stationsReceivingMultiStaBa
Map (originator, tid) pairs to the their index in baType.