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);
370 protection->muRts.SetCsRequired(
true);
372 payload->AddHeader(protection->muRts);
378 mpdu->GetHeader().SetDuration(
380 protection->muRtsTxVector,
393 protection->muRtsTxVector,
405 protection->muRtsTxVector);
437 for (
const auto& psdu : psduMap)
441 if (mpdu->IsQueued())
448 if (
const auto& hdr = psduMap.cbegin()->second->GetHeader(0); !hdr.GetAddr1().IsGroup())
453 for (
const auto& [staId, psdu] : psduMap)
455 if (psdu->GetAddr1().IsGroup())
476 auto it = std::find_if(
479 [&to](std::pair<uint16_t,
Ptr<WifiPsdu>> psdu) { return psdu.second->GetAddr1() == to; });
480 if (it != psduMap.end())
515 NS_LOG_DEBUG(address <<
" did not respond, hence it is no longer protected");
525 NS_LOG_DEBUG(
"Schedule another transmission in a SIFS after successful BSRP TF");
528 if (!StartTransmission(m_edca, Seconds(0)))
546HeFrameExchangeManager::SendPsduMap()
558 std::set<Mac48Address> staExpectResponseFrom;
565 if (m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE)
567 auto acknowledgment =
571 for (
const auto& psdu : m_psduMap)
573 if (acknowledgment->stationsSendBlockAckReqTo.contains(psdu.second->GetAddr1()))
576 std::set<uint8_t> tids = psdu.second->GetTids();
578 "Acknowledgment method incompatible with a Multi-TID A-MPDU");
579 uint8_t tid = *tids.begin();
583 m_mac->GetQosTxop(tid)->PrepareBlockAckRequest(psdu.second->GetAddr1(), tid);
584 m_edca->GetBaManager()->ScheduleBar(reqHdr, hdr);
588 if (!acknowledgment->stationsReplyingWithNormalAck.empty())
591 timerType = WifiTxTimer::WAIT_NORMAL_ACK_AFTER_DL_MU_PPDU;
593 &acknowledgment->stationsReplyingWithNormalAck.begin()->second.ackTxVector;
594 auto from = acknowledgment->stationsReplyingWithNormalAck.begin()->first;
595 psdu = GetPsduTo(from, m_psduMap);
597 mpdu = *psdu->begin();
598 staExpectResponseFrom.insert(from);
600 else if (!acknowledgment->stationsReplyingWithBlockAck.empty())
603 timerType = WifiTxTimer::WAIT_BLOCK_ACK;
605 &acknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
606 auto from = acknowledgment->stationsReplyingWithBlockAck.begin()->first;
607 psdu = GetPsduTo(from, m_psduMap);
608 staExpectResponseFrom.insert(from);
615 else if (m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_TF_MU_BAR)
617 auto acknowledgment =
static_cast<WifiDlMuTfMuBar*
>(m_txParams.m_acknowledgment.get());
624 std::map<uint16_t, CtrlBAckRequestHeader> recipients;
626 NS_ASSERT(!acknowledgment->stationsReplyingWithBlockAck.empty());
627 auto staIt = acknowledgment->stationsReplyingWithBlockAck.begin();
628 m_trigVector = staIt->second.blockAckTxVector;
629 while (staIt != acknowledgment->stationsReplyingWithBlockAck.end())
632 uint16_t staId = m_apMac->GetAssociationId(staIt->first, m_linkId);
634 m_trigVector.SetHeMuUserInfo(staId,
635 staIt->second.blockAckTxVector.GetHeMuUserInfo(staId));
636 recipients.emplace(staId, staIt->second.barHeader);
642 m_trigVector.SetLength(acknowledgment->ulLength);
644 m_triggerFrame = PrepareMuBar(m_trigVector, recipients);
651 for (
auto& station : acknowledgment->stationsReplyingWithBlockAck)
653 staExpectResponseFrom.insert(station.first);
656 Ptr<WifiPsdu> triggerPsdu = GetWifiPsdu(m_triggerFrame, acknowledgment->muBarTxVector);
657 Time txDuration = WifiPhy::CalculateTxDuration(triggerPsdu->GetSize(),
658 acknowledgment->muBarTxVector,
659 m_phy->GetPhyBand());
661 *acknowledgment->acknowledgmentTime -= (m_phy->GetSifs() + txDuration);
662 m_triggerFrame->GetHeader().SetDuration(GetPsduDurationId(txDuration, m_txParams));
665 &acknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
666 Time timeout = txDuration + m_phy->GetSifs() + m_phy->GetSlot() +
667 WifiPhy::CalculatePhyPreambleAndHeaderDuration(*responseTxVector);
669 m_txTimer.Set(WifiTxTimer::WAIT_BLOCK_ACKS_IN_TB_PPDU,
671 staExpectResponseFrom,
672 &HeFrameExchangeManager::BlockAcksInTbPpduTimeout,
675 staExpectResponseFrom.size());
676 m_channelAccessManager->NotifyAckTimeoutStartNow(
timeout);
678 ForwardPsduDown(triggerPsdu, acknowledgment->muBarTxVector);
683 hePhy->SetTrigVector(m_trigVector,
timeout);
691 else if (m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF)
693 auto acknowledgment =
static_cast<WifiDlMuAggregateTf*
>(m_txParams.m_acknowledgment.get());
699 for (
auto& station : acknowledgment->stationsReplyingWithBlockAck)
701 staExpectResponseFrom.insert(station.first);
704 auto psduMapIt = std::find_if(m_psduMap.begin(),
707 return psdu.second->GetAddr1() == station.first;
712 std::vector<Ptr<WifiMpdu>> mpduList(psduMapIt->second->begin(),
713 psduMapIt->second->end());
714 NS_ASSERT(mpduList.size() == psduMapIt->second->GetNMpdus());
717 station.second.blockAckTxVector.SetLength(acknowledgment->ulLength);
718 mpduList.push_back(PrepareMuBar(station.second.blockAckTxVector,
719 {{psduMapIt->first, station.second.barHeader}}));
720 psduMapIt->second = Create<WifiPsdu>(std::move(mpduList));
721 m_trigVector.SetHeMuUserInfo(
723 station.second.blockAckTxVector.GetHeMuUserInfo(psduMapIt->first));
726 timerType = WifiTxTimer::WAIT_BLOCK_ACKS_IN_TB_PPDU;
728 &acknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
729 m_trigVector.
SetLength(acknowledgment->ulLength);
734 else if (m_txParams.m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA)
738 mpdu = *m_psduMap.begin()->second->begin();
740 auto acknowledgment =
static_cast<WifiUlMuMultiStaBa*
>(m_txParams.m_acknowledgment.get());
743 for (
const auto& station : acknowledgment->stationsReceivingMultiStaBa)
745 staExpectResponseFrom.insert(station.first.first);
751 acknowledgment->baType.m_bitmapLen.clear();
753 timerType = WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF;
754 responseTxVector = &acknowledgment->tbPpduTxVector;
755 m_trigVector = GetTrigVector(m_muScheduler->GetUlMuInfo(m_linkId).trigger);
760 else if (m_txParams.m_acknowledgment->method == WifiAcknowledgment::NONE &&
761 !m_txParams.m_txVector.IsUlMu() &&
IsTrigger(m_psduMap))
763 CtrlTriggerHeader& trigger = m_muScheduler->GetUlMuInfo(m_linkId).trigger;
768 for (
const auto& userInfo : trigger)
770 auto staIt = m_apMac->GetStaList(m_linkId).find(userInfo.GetAid12());
771 NS_ASSERT(staIt != m_apMac->GetStaList(m_linkId).end());
772 staExpectResponseFrom.insert(staIt->second);
775 timerType = WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF;
776 txVector = trigger.GetHeTbTxVector(trigger.begin()->GetAid12());
777 responseTxVector = &txVector;
778 m_trigVector = GetTrigVector(m_muScheduler->GetUlMuInfo(m_linkId).trigger);
783 else if (m_txParams.m_txVector.IsUlMu() &&
784 m_txParams.m_acknowledgment->method == WifiAcknowledgment::ACK_AFTER_TB_PPDU)
787 timerType = WifiTxTimer::WAIT_BLOCK_ACK_AFTER_TB_PPDU;
788 NS_ASSERT(m_staMac && m_staMac->IsAssociated());
789 auto recv = m_psduMap.begin()->second->GetAddr1();
790 txVector = GetWifiRemoteStationManager()->GetBlockAckTxVector(recv, m_txParams.m_txVector);
791 responseTxVector = &txVector;
792 staExpectResponseFrom.insert(recv);
797 else if (m_txParams.m_txVector.IsUlMu() &&
798 m_txParams.m_acknowledgment->method == WifiAcknowledgment::NONE)
804 NS_ABORT_MSG(
"Unable to handle the selected acknowledgment method ("
805 << m_txParams.m_acknowledgment.get() <<
")");
810 for (
const auto& psdu : m_psduMap)
812 psduMap.emplace(psdu.first, psdu.second);
816 if (m_txParams.m_txVector.IsUlMu())
818 txDuration = HePhy::ConvertLSigLengthToHeTbPpduDuration(m_txParams.m_txVector.GetLength(),
819 m_txParams.m_txVector,
820 m_phy->GetPhyBand());
825 WifiPhy::CalculateTxDuration(psduMap, m_txParams.m_txVector, m_phy->GetPhyBand());
828 Time durationId = GetPsduDurationId(txDuration, m_txParams);
830 if (m_continueTxopAfterBsrpTf && m_edca && m_edca->GetTxopLimit(m_linkId).IsZero() &&
831 timerType == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF)
835 durationId += m_muScheduler->GetExtraTimeForBsrpTfDurationId(m_linkId);
838 for (
auto& psdu : m_psduMap)
840 psdu.second->SetDuration(durationId);
844 if (timerType == WifiTxTimer::NOT_RUNNING)
849 Simulator::Schedule(txDuration + m_phy->GetSifs(),
850 &HeFrameExchangeManager::SendPsduMap,
853 else if (!m_txParams.m_txVector.IsUlMu())
855 Simulator::Schedule(txDuration, &HeFrameExchangeManager::TransmissionSucceeded,
this);
860 Time timeout = txDuration + m_phy->GetSifs() + m_phy->GetSlot() +
861 WifiPhy::CalculatePhyPreambleAndHeaderDuration(*responseTxVector);
862 m_channelAccessManager->NotifyAckTimeoutStartNow(
timeout);
867 case WifiTxTimer::WAIT_NORMAL_ACK_AFTER_DL_MU_PPDU:
869 m_txTimer.Set(timerType,
871 staExpectResponseFrom,
872 &HeFrameExchangeManager::NormalAckTimeout,
875 m_txParams.m_txVector);
877 case WifiTxTimer::WAIT_BLOCK_ACK:
879 m_txTimer.Set(timerType,
881 staExpectResponseFrom,
882 &HeFrameExchangeManager::BlockAckTimeout,
885 m_txParams.m_txVector);
887 case WifiTxTimer::WAIT_BLOCK_ACKS_IN_TB_PPDU:
888 m_txTimer.Set(timerType,
890 staExpectResponseFrom,
891 &HeFrameExchangeManager::BlockAcksInTbPpduTimeout,
894 staExpectResponseFrom.size());
896 case WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF:
897 case WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF:
898 m_txTimer.Set(timerType,
900 staExpectResponseFrom,
901 &HeFrameExchangeManager::TbPpduTimeout,
904 staExpectResponseFrom.size());
906 case WifiTxTimer::WAIT_BLOCK_ACK_AFTER_TB_PPDU:
907 m_txTimer.Set(timerType,
909 staExpectResponseFrom,
910 &HeFrameExchangeManager::BlockAckAfterTbPpduTimeout,
912 m_psduMap.begin()->second,
913 m_txParams.m_txVector);
922 ForwardPsduMapDown(psduMap, m_txParams.m_txVector);
924 if (timerType == WifiTxTimer::WAIT_BLOCK_ACKS_IN_TB_PPDU ||
925 timerType == WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF ||
926 timerType == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF)
929 auto hePhy = StaticCast<HePhy>(m_phy->GetPhyEntity(responseTxVector->GetModulationClass()));
930 hePhy->SetTrigVector(m_trigVector, m_txTimer.GetDelayLeft());
932 else if (timerType == WifiTxTimer::NOT_RUNNING &&
933 (m_txParams.m_txVector.IsUlMu() ||
934 m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE))
938 Simulator::Schedule(txDuration, &WifiPsduMap::clear, &m_psduMap);
941 if (m_txTimer.IsRunning() && timerType != WifiTxTimer::WAIT_BLOCK_ACK_AFTER_TB_PPDU)
947 for (
const auto& address : staExpectResponseFrom)
949 if (!GetWifiRemoteStationManager()->GetEmlsrEnabled(address) ||
950 timerType == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF ||
951 m_protectedStas.contains(address))
953 m_sentFrameTo.insert(address);
967 auto sigBMode = hePhy->GetSigBMode(txVector);
971 for (
const auto& psdu : psduMap)
973 NS_LOG_DEBUG(
"Transmitting: [STAID=" << psdu.first <<
", " << *psdu.second <<
"]");
976 for (
const auto& [staId, psdu] : psduMap)
978 FinalizeMacHeader(psdu);
979 NotifyTxToEdca(psdu);
983 if (psduMap.size() > 1 || psduMap.begin()->second->IsAggregate() ||
984 psduMap.begin()->second->IsSingle())
989 auto txDuration = WifiPhy::CalculateTxDuration(psduMap, txVector, m_phy->GetPhyBand());
993 m_txNav =
Max(m_txNav, Simulator::Now() + txDuration + psduMap.cbegin()->second->GetDuration());
995 m_phy->Send(psduMap, txVector);
999HeFrameExchangeManager::PrepareMuBar(
const WifiTxVector& responseTxVector,
1000 std::map<uint16_t, CtrlBAckRequestHeader> recipients)
const
1007 SetTargetRssi(muBar);
1013 for (
auto& userInfo : muBar)
1015 auto recipientIt = recipients.find(userInfo.GetAid12());
1016 NS_ASSERT(recipientIt != recipients.end());
1019 userInfo.SetMuBarTriggerDepUserInfo(recipientIt->second);
1023 bar->AddHeader(muBar);
1031 rxAddress = Mac48Address::GetBroadcast();
1036 rxAddress = m_apMac->GetStaList(m_linkId).at(recipients.begin()->first);
1048 return Create<WifiMpdu>(bar, hdr);
1057 if (protection->
method == WifiProtection::MU_RTS_CTS)
1064 GetCtsTxVectorAfterMuRts(muRtsCtsProtection->muRts,
1065 muRtsCtsProtection->muRts.begin()->GetAid12());
1068 muRtsCtsProtection->muRts.GetSerializedSize() + WIFI_MAC_FCS_LENGTH;
1069 muRtsCtsProtection->protectionTime =
1070 WifiPhy::CalculateTxDuration(muRtsSize,
1071 muRtsCtsProtection->muRtsTxVector,
1072 m_phy->GetPhyBand()) +
1073 WifiPhy::CalculateTxDuration(
GetCtsSize(), ctsTxVector, m_phy->GetPhyBand()) +
1074 2 * m_phy->GetSifs();
1078 VhtFrameExchangeManager::CalculateProtectionTime(protection);
1091 if (acknowledgment->
method == WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE)
1098 NS_ABORT_IF(dlMuBarBaAcknowledgment->stationsReplyingWithNormalAck.size() +
1099 dlMuBarBaAcknowledgment->stationsReplyingWithBlockAck.size() >
1102 if (!dlMuBarBaAcknowledgment->stationsReplyingWithNormalAck.empty())
1105 dlMuBarBaAcknowledgment->stationsReplyingWithNormalAck.begin()->second;
1108 WifiPhy::CalculateTxDuration(
GetAckSize(), info.ackTxVector, m_phy->GetPhyBand());
1111 if (!dlMuBarBaAcknowledgment->stationsReplyingWithBlockAck.empty())
1114 dlMuBarBaAcknowledgment->stationsReplyingWithBlockAck.begin()->second;
1116 m_phy->GetSifs() + WifiPhy::CalculateTxDuration(
GetBlockAckSize(info.baType),
1117 info.blockAckTxVector,
1118 m_phy->GetPhyBand());
1121 for (
const auto& stations : dlMuBarBaAcknowledgment->stationsSendBlockAckReqTo)
1123 const auto& info = stations.second;
1124 duration += m_phy->GetSifs() +
1126 info.blockAckReqTxVector,
1127 m_phy->GetPhyBand()) +
1130 info.blockAckTxVector,
1131 m_phy->GetPhyBand());
1134 dlMuBarBaAcknowledgment->acknowledgmentTime = duration;
1139 else if (acknowledgment->
method == WifiAcknowledgment::DL_MU_TF_MU_BAR)
1141 auto dlMuTfMuBarAcknowledgment =
static_cast<WifiDlMuTfMuBar*
>(acknowledgment);
1145 for (
const auto& stations : dlMuTfMuBarAcknowledgment->stationsReplyingWithBlockAck)
1148 const auto& info = stations.second;
1149 NS_ASSERT(info.blockAckTxVector.GetHeMuUserInfoMap().size() == 1);
1150 uint16_t staId = info.blockAckTxVector.GetHeMuUserInfoMap().begin()->first;
1152 info.blockAckTxVector,
1153 m_phy->GetPhyBand(),
1156 if (currBlockAckDuration > duration)
1158 duration = currBlockAckDuration;
1164 WifiTxVector& txVector = dlMuTfMuBarAcknowledgment->stationsReplyingWithBlockAck.begin()
1165 ->second.blockAckTxVector;
1166 std::tie(dlMuTfMuBarAcknowledgment->ulLength, duration) =
1167 HePhy::ConvertHeTbPpduDurationToLSigLength(duration, txVector, m_phy->GetPhyBand());
1170 if (dlMuTfMuBarAcknowledgment->muBarTxVector.GetModulationClass() >=
WIFI_MOD_CLASS_VHT)
1173 muBarSize = MpduAggregator::GetSizeIfAggregated(muBarSize, 0);
1175 dlMuTfMuBarAcknowledgment->acknowledgmentTime =
1177 WifiPhy::CalculateTxDuration(muBarSize,
1178 dlMuTfMuBarAcknowledgment->muBarTxVector,
1179 m_phy->GetPhyBand()) +
1180 m_phy->GetSifs() + duration;
1185 else if (acknowledgment->
method == WifiAcknowledgment::DL_MU_AGGREGATE_TF)
1191 for (
const auto& stations : dlMuAggrTfAcknowledgment->stationsReplyingWithBlockAck)
1194 const auto& info = stations.second;
1195 NS_ASSERT(info.blockAckTxVector.GetHeMuUserInfoMap().size() == 1);
1196 uint16_t staId = info.blockAckTxVector.GetHeMuUserInfoMap().begin()->first;
1198 info.blockAckTxVector,
1199 m_phy->GetPhyBand(),
1202 if (currBlockAckDuration > duration)
1204 duration = currBlockAckDuration;
1211 dlMuAggrTfAcknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
1212 std::tie(dlMuAggrTfAcknowledgment->ulLength, duration) =
1213 HePhy::ConvertHeTbPpduDurationToLSigLength(duration, txVector, m_phy->GetPhyBand());
1214 dlMuAggrTfAcknowledgment->acknowledgmentTime = m_phy->GetSifs() + duration;
1219 else if (acknowledgment->
method == WifiAcknowledgment::UL_MU_MULTI_STA_BA)
1224 ulMuMultiStaBa->multiStaBaTxVector,
1225 m_phy->GetPhyBand());
1226 ulMuMultiStaBa->acknowledgmentTime = m_phy->GetSifs() + duration;
1231 else if (acknowledgment->
method == WifiAcknowledgment::ACK_AFTER_TB_PPDU)
1240 VhtFrameExchangeManager::CalculateAcknowledgmentTime(acknowledgment);
1245HeFrameExchangeManager::GetCtsModeAfterMuRts()
const
1250 : OfdmPhy::GetOfdmRate6Mbps();
1255 uint16_t staId)
const
1260 NS_ASSERT_MSG(userInfoIt != trigger.
end(),
"User Info field for AID=" << staId <<
" not found");
1263 if (uint8_t ru = userInfoIt->GetMuRtsRuAllocation(); ru < 65)
1281 auto txVector = GetWifiRemoteStationManager()->GetCtsTxVector(m_bssid, GetCtsModeAfterMuRts());
1283 txVector.SetChannelWidth(bw);
1289HeFrameExchangeManager::GetTxDuration(
uint32_t ppduPayloadSize,
1295 return VhtFrameExchangeManager::GetTxDuration(ppduPayloadSize, receiver, txParams);
1302 txParams.
m_acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF)
1306 NS_ASSERT_MSG(psduInfo,
"No information for " << receiver <<
" in TX params");
1307 NS_ASSERT_MSG(!psduInfo->seqNumbers.empty(),
"No sequence number for " << receiver);
1308 const auto tid = psduInfo->seqNumbers.cbegin()->first;
1310 ppduPayloadSize = MpduAggregator::GetSizeIfAggregated(
1311 GetMuBarSize({m_mac->GetBarTypeAsOriginator(receiver, tid)}),
1315 uint16_t staId = (txParams.
m_txVector.
IsDlMu() ? m_apMac->GetAssociationId(receiver, m_linkId)
1316 : m_staMac->GetAssociationId());
1317 Time psduDuration = WifiPhy::CalculateTxDuration(ppduPayloadSize,
1319 m_phy->GetPhyBand(),
1326HeFrameExchangeManager::TbPpduTimeout(
WifiPsduMap* psduMap, std::size_t nSolicitedStations)
1329 DoTbPpduTimeout(psduMap, nSolicitedStations,
true);
1334 std::size_t nSolicitedStations,
1335 bool updateFailedCw)
1337 const auto& staMissedTbPpduFrom = m_txTimer.GetStasExpectedToRespond();
1338 NS_LOG_FUNCTION(
this << psduMap << staMissedTbPpduFrom.size() << nSolicitedStations
1345 NS_ASSERT(!staMissedTbPpduFrom.empty());
1348 if (staMissedTbPpduFrom.size() == nSolicitedStations)
1352 psduMap->cbegin()->second->GetPayload(0)->PeekHeader(trigger);
1354 if (m_continueTxopAfterBsrpTf && m_edca->GetTxopLimit(m_linkId).IsZero() &&
1357 SendCfEndIfNeeded();
1360 TransmissionFailed(!updateFailedCw);
1362 else if (!m_multiStaBaEvent.IsPending())
1364 m_edca->ResetCw(m_linkId);
1365 TransmissionSucceeded();
1371 for (
const auto& address : staMissedTbPpduFrom)
1373 NS_LOG_DEBUG(address <<
" did not respond, hence it is no longer protected");
1374 m_protectedStas.erase(address);
1375 m_sentFrameTo.erase(address);
1377 if (m_protectedIfResponded)
1379 m_protectedStas.merge(m_sentFrameTo);
1381 m_sentFrameTo.clear();
1389 std::size_t nSolicitedStations)
1394 NS_ASSERT(m_txParams.m_acknowledgment &&
1395 (m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF ||
1396 m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_TF_MU_BAR));
1399 const auto& staMissedBlockAckFrom = m_txTimer.GetStasExpectedToRespond();
1400 NS_ASSERT(!staMissedBlockAckFrom.empty());
1402 if (staMissedBlockAckFrom.size() == nSolicitedStations)
1405 GetWifiRemoteStationManager()->ReportDataFailed(*psduMap->begin()->second->begin());
1411 m_triggerFrame =
nullptr;
1414 for (
const auto& sta : staMissedBlockAckFrom)
1416 auto psdu = GetPsduTo(sta, *psduMap);
1418 MissedBlockAck(psdu, m_txParams.m_txVector);
1423 if (staMissedBlockAckFrom.size() == nSolicitedStations)
1426 TransmissionFailed();
1430 m_edca->ResetCw(m_linkId);
1431 TransmissionSucceeded();
1441 GetWifiRemoteStationManager()->ReportDataFailed(*psdu->begin());
1443 MissedBlockAck(psdu, m_txParams.m_txVector);
1458 VhtFrameExchangeManager::NormalAckTimeout(mpdu, txVector);
1463 for (
auto& psdu : m_psduMap)
1467 if (mpdu->IsQueued())
1469 m_mac->GetTxopQueue(mpdu->GetQueueAc())->GetOriginal(mpdu)->GetHeader().SetRetry();
1470 mpdu->ResetInFlight(m_linkId);
1482 VhtFrameExchangeManager::BlockAckTimeout(psdu, txVector);
1487 for (
auto& psdu : m_psduMap)
1491 if (mpdu->IsQueued())
1493 mpdu->GetHeader().SetRetry();
1509 for (
const auto& userInfoField : trigger)
1512 userInfoField.GetAid12(),
1513 {userInfoField.GetRuAllocation(), userInfoField.GetUlMcs(), userInfoField.GetNss()});
1525 uint16_t staId = m_staMac->GetAssociationId();
1532 NS_ASSERT_MSG(heConfiguration,
"This STA has to be an HE station to send an HE TB PPDU");
1535 if (userInfoIt->IsUlTargetRssiMaxTxPower())
1537 NS_LOG_LOGIC(
"AP requested using the max transmit power (" << m_phy->GetTxPowerEnd()
1543 uint8_t powerLevel = GetWifiRemoteStationManager()->GetDefaultTxPowerLevel();
1561 auto optRssi = GetMostRecentRssi(triggerSender);
1567 auto reqTxPower =
dBm_u{
static_cast<double>(userInfoIt->GetUlTargetRssi() + pathLossDb)};
1570 uint8_t numPowerLevels = m_phy->GetNTxPower();
1571 if (numPowerLevels > 1)
1573 dBm_u step = (m_phy->GetTxPowerEnd() - m_phy->GetTxPowerStart()) / (numPowerLevels - 1);
1574 powerLevel =
static_cast<uint8_t
>(
1575 ceil((reqTxPower - m_phy->GetTxPowerStart()) /
1577 if (powerLevel > numPowerLevels)
1579 powerLevel = numPowerLevels;
1582 if (reqTxPower > m_phy->GetPower(powerLevel))
1584 NS_LOG_WARN(
"The requested power level (" << reqTxPower <<
"dBm) cannot be satisfied (max: "
1585 << m_phy->GetTxPowerEnd() <<
"dBm)");
1589 <<
"{pathLoss=" << pathLossDb <<
"dB, reqTxPower=" << reqTxPower <<
"dBm}"
1591 <<
"{powerLevel=" << +powerLevel <<
" -> " << m_phy->GetPower(powerLevel) <<
"dBm}"
1592 <<
" PHY power capa "
1593 <<
"{min=" << m_phy->GetTxPowerStart() <<
"dBm, max=" << m_phy->GetTxPowerEnd()
1594 <<
"dBm, levels:" << +numPowerLevels <<
"}");
1600HeFrameExchangeManager::GetMostRecentRssi(
const Mac48Address& address)
const
1602 return GetWifiRemoteStationManager()->GetMostRecentRssi(address);
1612 m_phy->GetPower(GetWifiRemoteStationManager()->GetDefaultTxPowerLevel())));
1613 for (
auto& userInfo : trigger)
1615 const auto staList = m_apMac->GetStaList(m_linkId);
1616 auto itAidAddr = staList.find(userInfo.GetAid12());
1618 auto optRssi = GetMostRecentRssi(itAidAddr->second);
1620 auto rssi =
static_cast<int8_t>(*optRssi);
1621 rssi = (rssi >= -20)
1623 : ((rssi <= -110) ? -110 : rssi);
1624 userInfo.SetUlTargetRssi(rssi);
1633 auto txVectorCopy = txVector;
1635 if (psdu->GetNMpdus() == 1 && psdu->GetHeader(0).IsTrigger())
1638 psdu->GetPayload(0)->PeekHeader(trigger);
1652 if (m_staMac !=
nullptr && m_staMac->IsAssociated() &&
1663 psdu = Create<const WifiPsdu>(Create<Packet>(), rts);
1667 GetWifiRemoteStationManager()->GetCtsTxVector(m_bssid, GetCtsModeAfterMuRts());
1670 VhtFrameExchangeManager::PostProcessFrame(psdu, txVectorCopy);
1680 if (!UlMuCsMediumIdle(trigger))
1682 NS_LOG_DEBUG(
"UL MU CS indicated medium busy, cannot send CTS");
1686 NS_ASSERT(m_staMac !=
nullptr && m_staMac->IsAssociated());
1687 WifiTxVector ctsTxVector = GetCtsTxVectorAfterMuRts(trigger, m_staMac->GetAssociationId());
1690 DoSendCtsAfterRts(muRtsHdr, ctsTxVector, muRtsSnr);
1700 txParams.
m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
1703 NS_ASSERT(!acknowledgment->stationsReceivingMultiStaBa.empty());
1706 blockAck.
SetType(acknowledgment->baType);
1710 for (
const auto& staInfo : acknowledgment->stationsReceivingMultiStaBa)
1712 receiver = staInfo.first.first;
1713 uint8_t tid = staInfo.first.second;
1714 std::size_t index = staInfo.second;
1716 blockAck.
SetAid11(m_apMac->GetAssociationId(receiver, m_linkId), index);
1722 NS_LOG_DEBUG(
"Multi-STA Block Ack: Sending All-ack to=" << receiver);
1727 if (acknowledgment->baType.m_bitmapLen.at(index) == 0)
1730 NS_LOG_DEBUG(
"Multi-STA Block Ack: Sending Ack to=" << receiver);
1738 auto agreement = m_mac->GetBaAgreementEstablishedAsRecipient(receiver, tid);
1740 agreement->get().FillBlockAckBitmap(blockAck, index);
1741 NS_LOG_DEBUG(
"Multi-STA Block Ack: Sending Block Ack with seq="
1743 <<
" tid=" << +tid);
1749 hdr.
SetAddr1(acknowledgment->stationsReceivingMultiStaBa.size() == 1
1751 : Mac48Address::GetBroadcast());
1757 packet->AddHeader(blockAck);
1759 GetWifiPsdu(Create<WifiMpdu>(packet, hdr), acknowledgment->multiStaBaTxVector);
1762 acknowledgment->multiStaBaTxVector,
1763 m_phy->GetPhyBand());
1775 if (m_edca->GetTxopLimit(m_linkId).IsZero())
1778 psdu->SetDuration(
Max(durationId - m_phy->GetSifs() - txDuration,
Seconds(0)));
1783 psdu->SetDuration(
Max(m_edca->GetRemainingTxop(m_linkId) - txDuration,
Seconds(0)));
1786 psdu->GetPayload(0)->AddPacketTag(m_muSnrTag);
1788 ForwardPsduDown(psdu, acknowledgment->multiStaBaTxVector);
1792 m_edca->ResetCw(m_linkId);
1794 Simulator::Schedule(txDuration, &HeFrameExchangeManager::TransmissionSucceeded,
this);
1803 NS_ASSERT(m_staMac && m_staMac->IsAssociated());
1805 NS_LOG_DEBUG(
"Received a Trigger Frame (basic variant) soliciting a transmission");
1807 if (!UlMuCsMediumIdle(trigger))
1818 std::vector<uint8_t> tids;
1819 uint16_t staId = m_staMac->GetAssociationId();
1822 for (uint8_t i = 0; i < 4; i++)
1825 tids.push_back(acIt->second.GetHighTid());
1826 tids.push_back(acIt->second.GetLowTid());
1838 Time ppduDuration = HePhy::ConvertLSigLengthToHeTbPpduDuration(trigger.
GetUlLength(),
1840 m_phy->GetPhyBand());
1842 for (
const auto& tid : tids)
1846 if (!m_mac->GetBaAgreementEstablishedAsOriginator(hdr.
GetAddr2(), tid))
1856 if (
auto mpdu = GetBar(edca->GetAccessCategory(), tid, hdr.
GetAddr2());
1857 mpdu && TryAddMpdu(mpdu, txParams, ppduDuration))
1860 psdu = Create<WifiPsdu>(mpdu,
true);
1866 GetWifiRemoteStationManager()->GetMldAddress(hdr.
GetAddr2()).value_or(hdr.
GetAddr2());
1867 if (
auto mpdu = edca->PeekNextMpdu(m_linkId, tid, receiver))
1869 mpdu = CreateAliasIfNeeded(mpdu);
1870 if (
auto item = edca->GetNextMpdu(m_linkId, mpdu, txParams, ppduDuration,
false))
1873 std::vector<Ptr<WifiMpdu>> mpduList =
1874 m_mpduAggregator->GetNextAmpdu(item, txParams, ppduDuration);
1875 psdu = (mpduList.size() > 1 ? Create<WifiPsdu>(std::move(mpduList))
1876 : Create<WifiPsdu>(item,
true));
1884 psdu->SetDuration(hdr.
GetDuration() - m_phy->GetSifs() - ppduDuration);
1885 SendPsduMapWithProtection(
WifiPsduMap{{staId, psdu}}, txParams);
1890 SendQosNullFramesInTbPpdu(trigger, hdr);
1900 NS_ASSERT(m_staMac && m_staMac->IsAssociated());
1904 if (!UlMuCsMediumIdle(trigger))
1910 GetWifiRemoteStationManager()->GetMldAddress(hdr.
GetAddr2()).value_or(hdr.
GetAddr2());
1913 header.
SetAddr2(m_mac->GetAddress());
1928 Time ppduDuration = HePhy::ConvertLSigLengthToHeTbPpduDuration(trigger.
GetUlLength(),
1930 m_phy->GetPhyBand());
1933 std::vector<Ptr<WifiMpdu>> mpduList;
1935 for (uint8_t tid = 0; tid < 8; ++tid)
1937 if (!m_mac->GetBaAgreementEstablishedAsOriginator(hdr.
GetAddr2(), tid))
1939 NS_LOG_DEBUG(
"Skipping tid=" << +tid <<
" because no agreement established");
1949 auto mpdu = Create<WifiMpdu>(Create<Packet>(), header);
1950 mpdu = CreateAliasIfNeeded(mpdu);
1952 UpdateTxDuration(header.
GetAddr1(), txParams);
1963 NS_LOG_DEBUG(
"Aggregating a QoS Null frame with tid=" << +tid);
1965 mpduList.push_back(mpdu);
1968 if (mpduList.empty())
1970 NS_LOG_DEBUG(
"Not enough time to send a QoS Null frame");
1974 Ptr<WifiPsdu> psdu = (mpduList.size() > 1 ? Create<WifiPsdu>(std::move(mpduList))
1975 : Create<WifiPsdu>(mpduList.front(),
true));
1976 uint16_t staId = m_staMac->GetAssociationId();
1977 SendPsduMapWithProtection(
WifiPsduMap{{staId, psdu}}, txParams);
1988 auto agreement = m_mac->GetBaAgreementEstablishedAsRecipient(m_bssid, tid);
1992 NS_LOG_DEBUG(
"There's not a valid agreement for this BlockAckReq");
1996 if (!UlMuCsMediumIdle(trigger))
2002 auto txVector = GetHeTbTxVector(trigger, m_bssid);
2003 SendBlockAck(*agreement, durationId, txVector, snr);
2017 const auto ra = psdu->GetAddr1();
2018 const auto ta = psdu->GetAddr2();
2019 const auto bssid = psdu->GetHeader(0).GetAddr3();
2022 if (ra == m_bssid || ta == m_bssid || bssid == m_bssid)
2030 if (psdu->GetHeader(0).IsCtl() && ta == empty && ra == m_txopHolder)
2044 if (bssid != empty && bssid != m_bssid)
2052 if (bssid == empty && ta != empty && ra != empty && ta != m_bssid && ra != m_bssid)
2065 const auto bssColor = m_mac->GetHeConfiguration()->m_bssColor;
2068 return bssColor != 0 && bssColor == txVector.
GetBssColor();
2076 if (!psdu->HasNav())
2081 if (psdu->GetAddr1() == m_self)
2091 if (!IsIntraBssPpdu(psdu, txVector))
2093 NS_LOG_DEBUG(
"PPDU not classified as intra-BSS, update the basic NAV");
2094 VhtFrameExchangeManager::UpdateNav(psdu, txVector);
2098 NS_LOG_DEBUG(
"PPDU classified as intra-BSS, update the intra-BSS NAV");
2099 Time duration = psdu->GetDuration();
2102 if (psdu->GetHeader(0).IsCfEnd())
2108 NS_LOG_DEBUG(
"Received CF-End, resetting the intra-BSS NAV");
2109 IntraBssNavResetTimeout();
2115 auto intraBssNavEnd = Simulator::Now() + duration;
2116 if (intraBssNavEnd > m_intraBssNavEnd)
2118 m_intraBssNavEnd = intraBssNavEnd;
2119 NS_LOG_DEBUG(
"Updated intra-BSS NAV=" << m_intraBssNavEnd);
2130 if (psdu->GetHeader(0).IsRts())
2133 GetWifiRemoteStationManager()->GetCtsTxVector(psdu->GetAddr2(), txVector.
GetMode());
2134 auto navResetDelay =
2135 2 * m_phy->GetSifs() +
2136 WifiPhy::CalculateTxDuration(
GetCtsSize(), ctsTxVector, m_phy->GetPhyBand()) +
2137 WifiPhy::CalculatePhyPreambleAndHeaderDuration(ctsTxVector) + 2 * m_phy->GetSlot();
2138 m_intraBssNavResetEvent =
2139 Simulator::Schedule(navResetDelay,
2140 &HeFrameExchangeManager::IntraBssNavResetTimeout,
2144 NS_LOG_DEBUG(
"Current intra-BSS NAV=" << m_intraBssNavEnd);
2146 m_channelAccessManager->NotifyNavStartNow(duration);
2150HeFrameExchangeManager::ClearTxopHolderIfNeeded()
2153 if (m_intraBssNavEnd <= Simulator::Now())
2155 m_txopHolder.reset();
2160HeFrameExchangeManager::NavResetTimeout()
2163 m_navEnd = Simulator::Now();
2166 Time intraBssNav = Simulator::GetDelayLeft(m_intraBssNavResetEvent);
2167 m_channelAccessManager->NotifyNavResetNow(intraBssNav);
2171HeFrameExchangeManager::IntraBssNavResetTimeout()
2174 m_intraBssNavEnd = Simulator::Now();
2175 ClearTxopHolderIfNeeded();
2177 Time basicNav = Simulator::GetDelayLeft(m_navResetEvent);
2178 m_channelAccessManager->NotifyNavResetNow(basicNav);
2181std::optional<Mac48Address>
2192 return VhtFrameExchangeManager::FindTxopHolder(hdr, txVector);
2194 return std::nullopt;
2198HeFrameExchangeManager::VirtualCsMediumIdle()
const
2203 return m_navEnd <= Simulator::Now() && m_intraBssNavEnd <= Simulator::Now();
2219 const Time now = Simulator::Now();
2226 NS_ASSERT_MSG(m_staMac,
"UL MU CS is only performed by non-AP STAs");
2229 "No User Info field for STA (" << m_self
2230 <<
") AID=" << m_staMac->GetAssociationId());
2232 std::set<uint8_t> indices;
2236 auto ctsTxVector = GetCtsTxVectorAfterMuRts(trigger, m_staMac->GetAssociationId());
2237 auto bw = ctsTxVector.GetChannelWidth();
2238 indices = m_phy->GetOperatingChannel().GetAll20MHzChannelIndicesInPrimary(bw);
2243 m_phy->GetOperatingChannel().Get20MHzIndicesCoveringRu(userInfoIt->GetRuAllocation(),
2246 return !m_channelAccessManager->GetPer20MHzBusy(indices);
2255 NS_LOG_FUNCTION(
this << *mpdu << rxSignalInfo << txVector << inAmpdu);
2258 NS_ASSERT(mpdu->GetHeader().GetAddr1().IsGroup() || mpdu->GetHeader().GetAddr1() == m_self);
2262 if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
2263 m_txTimer.GetReason() == WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF)
2266 NS_ASSERT(m_txParams.m_acknowledgment &&
2267 m_txParams.m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
2268 auto acknowledgment =
static_cast<WifiUlMuMultiStaBa*
>(m_txParams.m_acknowledgment.get());
2271 if (!m_txTimer.GetStasExpectedToRespond().contains(sender))
2273 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2279 NS_LOG_DEBUG(
"Received a BlockAckReq in a TB PPDU from " << sender);
2282 mpdu->GetPacket()->PeekHeader(blockAckReq);
2285 GetBaManager(tid)->NotifyGotBlockAckRequest(
2286 m_mac->GetMldAddress(sender).value_or(sender),
2291 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, tid), index);
2292 acknowledgment->baType.m_bitmapLen.push_back(
2293 m_mac->GetBaTypeAsRecipient(sender, tid).m_bitmapLen.at(0));
2295 m_muSnrTag.Set(staId, rxSignalInfo.
snr);
2299 NS_LOG_DEBUG(
"Received an S-MPDU in a TB PPDU from " << sender <<
" (" << *mpdu <<
")");
2302 GetBaManager(tid)->NotifyGotMpdu(mpdu);
2305 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, tid), index);
2306 acknowledgment->baType.m_bitmapLen.push_back(0);
2308 m_muSnrTag.Set(staId, rxSignalInfo.
snr);
2317 VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
2322 if (!acknowledgment->stationsReceivingMultiStaBa.empty() && !m_multiStaBaEvent.IsPending())
2324 m_multiStaBaEvent = Simulator::Schedule(m_phy->GetSifs(),
2325 &HeFrameExchangeManager::SendMultiStaBlockAck,
2327 std::cref(m_txParams),
2328 mpdu->GetHeader().GetDuration());
2332 m_txTimer.GotResponseFrom(sender);
2334 if (m_txTimer.GetStasExpectedToRespond().empty())
2338 m_channelAccessManager->NotifyAckTimeoutResetNow();
2340 if (!m_multiStaBaEvent.IsPending())
2345 m_edca->ResetCw(m_linkId);
2346 TransmissionSucceeded();
2354 if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
2355 m_txTimer.GetReason() == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF &&
2358 const auto& sender = hdr.
GetAddr2();
2360 if (!m_txTimer.GetStasExpectedToRespond().contains(sender))
2362 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2367 NS_LOG_WARN(
"No QoS Null frame in the received MPDU");
2371 NS_LOG_DEBUG(
"Received a QoS Null frame in a TB PPDU from " << sender);
2372 ReceivedQosNullAfterBsrpTf(sender);
2380 if (hdr.
IsCts() && m_txTimer.IsRunning() &&
2381 m_txTimer.GetReason() == WifiTxTimer::WAIT_CTS && m_psduMap.size() == 1)
2386 Mac48Address sender = m_psduMap.begin()->second->GetAddr1();
2390 mpdu->GetPacket()->PeekPacketTag(tag);
2391 GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
2392 GetWifiRemoteStationManager()->ReportRtsOk(m_psduMap.begin()->second->GetHeader(0),
2398 m_channelAccessManager->NotifyCtsTimeoutResetNow();
2399 ProtectionCompleted();
2401 else if (hdr.
IsCts() && m_txTimer.IsRunning() &&
2402 m_txTimer.GetReason() == WifiTxTimer::WAIT_CTS_AFTER_MU_RTS)
2407 NS_LOG_DEBUG(
"Received a CTS frame in response to an MU-RTS");
2410 m_channelAccessManager->NotifyCtsTimeoutResetNow();
2411 ProtectionCompleted();
2413 else if (hdr.
IsAck() && m_txTimer.IsRunning() &&
2414 m_txTimer.GetReason() == WifiTxTimer::WAIT_NORMAL_ACK_AFTER_DL_MU_PPDU)
2418 NS_ASSERT(m_txParams.m_acknowledgment->method ==
2419 WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE);
2421 auto acknowledgment =
2423 NS_ASSERT(acknowledgment->stationsReplyingWithNormalAck.size() == 1);
2425 uint16_t staId = m_apMac->GetAssociationId(
2426 acknowledgment->stationsReplyingWithNormalAck.begin()->first,
2428 auto it = m_psduMap.find(staId);
2431 acknowledgment->stationsReplyingWithNormalAck.begin()->first);
2433 mpdu->GetPacket()->PeekPacketTag(tag);
2434 ReceivedNormalAck(*it->second->begin(),
2435 m_txParams.m_txVector,
2448 m_txTimer.GetReason() == WifiTxTimer::WAIT_BLOCK_ACKS_IN_TB_PPDU)
2451 NS_LOG_DEBUG(
"Received BlockAck in TB PPDU from=" << sender);
2454 mpdu->GetPacket()->PeekPacketTag(tag);
2458 mpdu->GetPacket()->PeekHeader(blockAck);
2460 std::pair<uint16_t, uint16_t> ret =
2461 GetBaManager(tid)->NotifyGotBlockAck(m_linkId,
2463 m_mac->GetMldAddress(sender).value_or(sender),
2465 GetWifiRemoteStationManager()->ReportAmpduTxStatus(sender,
2470 m_txParams.m_txVector);
2473 if (!m_txTimer.GetStasExpectedToRespond().contains(sender))
2475 NS_LOG_WARN(
"Received a BlockAck from an unexpected stations: " << sender);
2479 m_txTimer.GotResponseFrom(sender);
2481 if (m_txTimer.GetStasExpectedToRespond().empty())
2485 m_channelAccessManager->NotifyAckTimeoutResetNow();
2489 m_triggerFrame =
nullptr;
2492 m_edca->ResetCw(m_linkId);
2494 TransmissionSucceeded();
2497 else if (hdr.
IsBlockAck() && m_txTimer.IsRunning() &&
2498 m_txTimer.GetReason() == WifiTxTimer::WAIT_BLOCK_ACK_AFTER_TB_PPDU)
2501 mpdu->GetPacket()->PeekHeader(blockAck);
2504 "A Multi-STA BlockAck is expected after a TB PPDU");
2506 m_txTimer.GotResponseFrom(hdr.
GetAddr2());
2508 NS_ASSERT(m_staMac && m_staMac->IsAssociated());
2511 NS_LOG_DEBUG(
"The sender is not the AP we are associated with");
2515 uint16_t staId = m_staMac->GetAssociationId();
2518 if (indices.empty())
2520 NS_LOG_DEBUG(
"No Per AID TID Info subfield intended for me");
2525 mpdu->GetPacket()->PeekPacketTag(tag);
2528 for (
const auto& index : indices)
2535 NS_ABORT_IF(m_psduMap.empty() || m_psduMap.begin()->first != staId);
2536 GetBaManager(tid)->NotifyGotAck(m_linkId, *m_psduMap.at(staId)->begin());
2545 NS_ABORT_IF(m_psduMap.empty() || m_psduMap.begin()->first != staId);
2546 std::set<uint8_t> tids = m_psduMap.at(staId)->GetTids();
2547 NS_ABORT_MSG_IF(tids.size() > 1,
"Multi-TID A-MPDUs not supported yet");
2548 tid = *tids.begin();
2551 std::pair<uint16_t, uint16_t> ret = GetBaManager(tid)->NotifyGotBlockAck(
2557 GetWifiRemoteStationManager()->ReportAmpduTxStatus(hdr.
GetAddr2(),
2562 m_txParams.m_txVector);
2565 if (m_psduMap.at(staId)->GetHeader(0).IsQosData() &&
2567 || std::any_of(blockAck.
GetBitmap(index).begin(),
2569 [](uint8_t b) { return b != 0; })))
2571 NS_ASSERT(m_psduMap.at(staId)->GetHeader(0).HasData());
2572 NS_ASSERT(m_psduMap.at(staId)->GetHeader(0).GetQosTid() == tid);
2577 m_mac->GetQosTxop(tid)->StartMuEdcaTimerNow(m_linkId);
2583 m_channelAccessManager->NotifyAckTimeoutResetNow();
2585 for (
const auto& [staId, psdu] : m_psduMap)
2587 if (psdu->GetNMpdus() == 1 && psdu->GetHeader(0).IsBlockAckReq())
2594 else if (hdr.
IsBlockAck() && m_txTimer.IsRunning() &&
2595 m_txTimer.GetReason() == WifiTxTimer::WAIT_BLOCK_ACK)
2601 VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
2614 m_triggerFrameInAmpdu =
true;
2619 mpdu->GetPacket()->PeekHeader(trigger);
2630 uint16_t staId = m_staMac->GetAssociationId();
2635 NS_LOG_DEBUG(
"Received MU-RTS Trigger Frame from=" << sender);
2636 GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
2646 m_sendCtsEvent = Simulator::Schedule(m_phy->GetSifs(),
2647 &HeFrameExchangeManager::SendCtsAfterMuRts,
2656 NS_LOG_DEBUG(
"Received MU-BAR Trigger Frame from=" << sender);
2657 GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
2665 GetBaManager(tid)->NotifyGotBlockAckRequest(
2666 m_mac->GetMldAddress(sender).value_or(sender),
2670 Simulator::Schedule(m_phy->GetSifs(),
2671 &HeFrameExchangeManager::ReceiveMuBarTrigger,
2680 Simulator::Schedule(m_phy->GetSifs(),
2681 &HeFrameExchangeManager::ReceiveBasicTrigger,
2686 else if (trigger.
IsBsrp())
2688 Simulator::Schedule(m_phy->GetSifs(),
2689 &HeFrameExchangeManager::SendQosNullFramesInTbPpdu,
2698 VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
2706 VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
2714 const std::vector<bool>& perMpduStatus)
2716 std::set<uint8_t> tids = psdu->GetTids();
2718 if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
2719 m_txTimer.GetReason() == WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF)
2722 NS_ASSERT(m_txParams.m_acknowledgment &&
2723 m_txParams.m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
2724 auto acknowledgment =
static_cast<WifiUlMuMultiStaBa*
>(m_txParams.m_acknowledgment.get());
2727 if (!m_txTimer.GetStasExpectedToRespond().contains(sender))
2729 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2733 NS_LOG_DEBUG(
"Received an A-MPDU in a TB PPDU from " << sender <<
" (" << *psdu <<
")");
2735 if (std::any_of(tids.begin(), tids.end(), [&psdu](uint8_t tid) {
2736 return psdu->GetAckPolicyForTid(tid) == WifiMacHeader::NORMAL_ACK;
2739 if (std::all_of(perMpduStatus.cbegin(), perMpduStatus.cend(), [](
bool v) { return v; }))
2742 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, 14),
2744 acknowledgment->baType.m_bitmapLen.push_back(0);
2750 for (
const auto& tid : tids)
2752 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, tid),
2754 acknowledgment->baType.m_bitmapLen.push_back(
2755 m_mac->GetBaTypeAsRecipient(sender, tid).m_bitmapLen.at(0));
2759 m_muSnrTag.Set(staId, rxSignalInfo.
snr);
2763 if (!acknowledgment->stationsReceivingMultiStaBa.empty() && !m_multiStaBaEvent.IsPending())
2765 m_multiStaBaEvent = Simulator::Schedule(m_phy->GetSifs(),
2766 &HeFrameExchangeManager::SendMultiStaBlockAck,
2768 std::cref(m_txParams),
2769 psdu->GetDuration());
2773 m_txTimer.GotResponseFrom(sender);
2775 if (m_txTimer.GetStasExpectedToRespond().empty())
2779 m_channelAccessManager->NotifyAckTimeoutResetNow();
2781 if (!m_multiStaBaEvent.IsPending())
2786 m_edca->ResetCw(m_linkId);
2787 TransmissionSucceeded();
2795 if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
2796 m_txTimer.GetReason() == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF)
2800 if (!m_txTimer.GetStasExpectedToRespond().contains(sender))
2802 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2805 if (std::none_of(psdu->begin(), psdu->end(), [](
Ptr<WifiMpdu> mpdu) {
2806 return mpdu->GetHeader().IsQosData() && !mpdu->GetHeader().HasData();
2809 NS_LOG_WARN(
"No QoS Null frame in the received PSDU");
2813 NS_LOG_DEBUG(
"Received QoS Null frames in a TB PPDU from " << sender);
2814 ReceivedQosNullAfterBsrpTf(sender);
2820 if (m_triggerFrameInAmpdu)
2823 auto psduIt = psdu->begin();
2824 while (psduIt != psdu->end())
2826 if ((*psduIt)->GetHeader().IsTrigger())
2828 ReceiveMpdu(*psduIt, rxSignalInfo, txVector,
false);
2833 m_triggerFrameInAmpdu =
false;
2838 VhtFrameExchangeManager::EndReceiveAmpdu(psdu, rxSignalInfo, txVector, perMpduStatus);
2847 m_txTimer.GetReason() == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF);
2850 m_txTimer.GotResponseFrom(sender);
2852 if (m_txTimer.GetStasExpectedToRespond().empty())
2855 m_channelAccessManager->NotifyAckTimeoutResetNow();
2859 m_edca->ResetCw(m_linkId);
2860 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)
void DoCtsTimeout(Ptr< WifiPsdu > psdu)
Take required actions when the CTS timer fired after sending an RTS to protect the given PSDU expires...
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
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager() const
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.
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
Ptr< WifiMpdu > DropMpduIfRetryLimitReached(Ptr< WifiPsdu > psdu)
Wrapper for the GetMpdusToDropOnTxFailure function of the remote station manager that additionally dr...
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 bool GetUpdateCwOnCtsTimeout() const
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 DoCtsAfterMuRtsTimeout(const WifiPsduMap &psduMap)
Called when no CTS frame is received after an MU-RTS.
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...
void ReleaseSequenceNumbers(Ptr< const WifiPsdu > psdu) const override
Make the sequence numbers of MPDUs included in the given PSDU available again if the MPDUs have never...
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
void TransmissionFailed(bool forceCurrentCw=false) override
Take necessary actions upon a transmission failure.
virtual bool SendCfEndIfNeeded()
Send a CF-End frame to indicate the completion of the TXOP, provided that the remaining duration is l...
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)
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.
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).
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).
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.