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 <<
"input {pathLoss=" << pathLossDb <<
"dB, reqTxPower=" << reqTxPower <<
"dBm}"
1590 <<
" output {powerLevel=" << +powerLevel <<
" -> " << m_phy->GetPower(powerLevel)
1592 <<
" PHY power capa {min=" << m_phy->GetTxPowerStart() <<
"dBm, max="
1593 << m_phy->GetTxPowerEnd() <<
"dBm, levels:" << +numPowerLevels <<
"}");
1599HeFrameExchangeManager::GetMostRecentRssi(
const Mac48Address& address)
const
1601 return GetWifiRemoteStationManager()->GetMostRecentRssi(address);
1611 m_phy->GetPower(GetWifiRemoteStationManager()->GetDefaultTxPowerLevel())));
1612 for (
auto& userInfo : trigger)
1614 const auto staList = m_apMac->GetStaList(m_linkId);
1615 auto itAidAddr = staList.find(userInfo.GetAid12());
1617 auto optRssi = GetMostRecentRssi(itAidAddr->second);
1619 auto rssi =
static_cast<int8_t>(*optRssi);
1620 rssi = (rssi >= -20)
1622 : ((rssi <= -110) ? -110 : rssi);
1623 userInfo.SetUlTargetRssi(rssi);
1632 auto txVectorCopy = txVector;
1634 if (psdu->GetNMpdus() == 1 && psdu->GetHeader(0).IsTrigger())
1637 psdu->GetPayload(0)->PeekHeader(trigger);
1651 if (m_staMac !=
nullptr && m_staMac->IsAssociated() &&
1662 psdu = Create<const WifiPsdu>(Create<Packet>(), rts);
1666 GetWifiRemoteStationManager()->GetCtsTxVector(m_bssid, GetCtsModeAfterMuRts());
1669 VhtFrameExchangeManager::PostProcessFrame(psdu, txVectorCopy);
1679 if (!UlMuCsMediumIdle(trigger))
1681 NS_LOG_DEBUG(
"UL MU CS indicated medium busy, cannot send CTS");
1685 NS_ASSERT(m_staMac !=
nullptr && m_staMac->IsAssociated());
1686 WifiTxVector ctsTxVector = GetCtsTxVectorAfterMuRts(trigger, m_staMac->GetAssociationId());
1689 DoSendCtsAfterRts(muRtsHdr, ctsTxVector, muRtsSnr);
1699 txParams.
m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
1702 NS_ASSERT(!acknowledgment->stationsReceivingMultiStaBa.empty());
1705 blockAck.
SetType(acknowledgment->baType);
1709 for (
const auto& staInfo : acknowledgment->stationsReceivingMultiStaBa)
1711 receiver = staInfo.first.first;
1712 uint8_t tid = staInfo.first.second;
1713 std::size_t index = staInfo.second;
1715 blockAck.
SetAid11(m_apMac->GetAssociationId(receiver, m_linkId), index);
1721 NS_LOG_DEBUG(
"Multi-STA Block Ack: Sending All-ack to=" << receiver);
1726 if (acknowledgment->baType.m_bitmapLen.at(index) == 0)
1729 NS_LOG_DEBUG(
"Multi-STA Block Ack: Sending Ack to=" << receiver);
1737 auto agreement = m_mac->GetBaAgreementEstablishedAsRecipient(receiver, tid);
1739 agreement->get().FillBlockAckBitmap(blockAck, index);
1740 NS_LOG_DEBUG(
"Multi-STA Block Ack: Sending Block Ack with seq="
1742 <<
" tid=" << +tid);
1748 hdr.
SetAddr1(acknowledgment->stationsReceivingMultiStaBa.size() == 1
1750 : Mac48Address::GetBroadcast());
1756 packet->AddHeader(blockAck);
1758 GetWifiPsdu(Create<WifiMpdu>(packet, hdr), acknowledgment->multiStaBaTxVector);
1761 acknowledgment->multiStaBaTxVector,
1762 m_phy->GetPhyBand());
1774 if (m_edca->GetTxopLimit(m_linkId).IsZero())
1777 psdu->SetDuration(
Max(durationId - m_phy->GetSifs() - txDuration,
Seconds(0)));
1782 psdu->SetDuration(
Max(m_edca->GetRemainingTxop(m_linkId) - txDuration,
Seconds(0)));
1785 psdu->GetPayload(0)->AddPacketTag(m_muSnrTag);
1787 ForwardPsduDown(psdu, acknowledgment->multiStaBaTxVector);
1791 m_edca->ResetCw(m_linkId);
1793 Simulator::Schedule(txDuration, &HeFrameExchangeManager::TransmissionSucceeded,
this);
1802 NS_ASSERT(m_staMac && m_staMac->IsAssociated());
1804 NS_LOG_DEBUG(
"Received a Trigger Frame (basic variant) soliciting a transmission");
1806 if (!UlMuCsMediumIdle(trigger))
1817 std::vector<uint8_t> tids;
1818 uint16_t staId = m_staMac->GetAssociationId();
1821 for (uint8_t i = 0; i < 4; i++)
1824 tids.push_back(acIt->second.GetHighTid());
1825 tids.push_back(acIt->second.GetLowTid());
1837 Time ppduDuration = HePhy::ConvertLSigLengthToHeTbPpduDuration(trigger.
GetUlLength(),
1839 m_phy->GetPhyBand());
1841 for (
const auto& tid : tids)
1845 if (!m_mac->GetBaAgreementEstablishedAsOriginator(hdr.
GetAddr2(), tid))
1855 if (
auto mpdu = GetBar(edca->GetAccessCategory(), tid, hdr.
GetAddr2());
1856 mpdu && TryAddMpdu(mpdu, txParams, ppduDuration))
1859 psdu = Create<WifiPsdu>(mpdu,
true);
1865 GetWifiRemoteStationManager()->GetMldAddress(hdr.
GetAddr2()).value_or(hdr.
GetAddr2());
1866 if (
auto mpdu = edca->PeekNextMpdu(m_linkId, tid, receiver))
1868 mpdu = CreateAliasIfNeeded(mpdu);
1869 if (
auto item = edca->GetNextMpdu(m_linkId, mpdu, txParams, ppduDuration,
false))
1872 std::vector<Ptr<WifiMpdu>> mpduList =
1873 m_mpduAggregator->GetNextAmpdu(item, txParams, ppduDuration);
1874 psdu = (mpduList.size() > 1 ? Create<WifiPsdu>(std::move(mpduList))
1875 : Create<WifiPsdu>(item,
true));
1883 psdu->SetDuration(hdr.
GetDuration() - m_phy->GetSifs() - ppduDuration);
1884 SendPsduMapWithProtection(
WifiPsduMap{{staId, psdu}}, txParams);
1889 SendQosNullFramesInTbPpdu(trigger, hdr);
1899 NS_ASSERT(m_staMac && m_staMac->IsAssociated());
1903 if (!UlMuCsMediumIdle(trigger))
1909 GetWifiRemoteStationManager()->GetMldAddress(hdr.
GetAddr2()).value_or(hdr.
GetAddr2());
1912 header.
SetAddr2(m_mac->GetAddress());
1927 Time ppduDuration = HePhy::ConvertLSigLengthToHeTbPpduDuration(trigger.
GetUlLength(),
1929 m_phy->GetPhyBand());
1932 std::vector<Ptr<WifiMpdu>> mpduList;
1934 for (uint8_t tid = 0; tid < 8; ++tid)
1936 if (!m_mac->GetBaAgreementEstablishedAsOriginator(hdr.
GetAddr2(), tid))
1938 NS_LOG_DEBUG(
"Skipping tid=" << +tid <<
" because no agreement established");
1948 auto mpdu = Create<WifiMpdu>(Create<Packet>(), header);
1949 mpdu = CreateAliasIfNeeded(mpdu);
1951 UpdateTxDuration(header.
GetAddr1(), txParams);
1962 NS_LOG_DEBUG(
"Aggregating a QoS Null frame with tid=" << +tid);
1964 mpduList.push_back(mpdu);
1967 if (mpduList.empty())
1969 NS_LOG_DEBUG(
"Not enough time to send a QoS Null frame");
1973 Ptr<WifiPsdu> psdu = (mpduList.size() > 1 ? Create<WifiPsdu>(std::move(mpduList))
1974 : Create<WifiPsdu>(mpduList.front(),
true));
1975 uint16_t staId = m_staMac->GetAssociationId();
1976 SendPsduMapWithProtection(
WifiPsduMap{{staId, psdu}}, txParams);
1987 auto agreement = m_mac->GetBaAgreementEstablishedAsRecipient(m_bssid, tid);
1991 NS_LOG_DEBUG(
"There's not a valid agreement for this BlockAckReq");
1995 if (!UlMuCsMediumIdle(trigger))
2001 auto txVector = GetHeTbTxVector(trigger, m_bssid);
2002 SendBlockAck(*agreement, durationId, txVector, snr);
2016 const auto ra = psdu->GetAddr1();
2017 const auto ta = psdu->GetAddr2();
2018 const auto bssid = psdu->GetHeader(0).GetAddr3();
2021 if (ra == m_bssid || ta == m_bssid || bssid == m_bssid)
2029 if (psdu->GetHeader(0).IsCtl() && ta == empty && ra == m_txopHolder)
2043 if (bssid != empty && bssid != m_bssid)
2051 if (bssid == empty && ta != empty && ra != empty && ta != m_bssid && ra != m_bssid)
2064 const auto bssColor = m_mac->GetHeConfiguration()->m_bssColor;
2067 return bssColor != 0 && bssColor == txVector.
GetBssColor();
2075 if (!psdu->HasNav())
2080 if (psdu->GetAddr1() == m_self)
2090 if (!IsIntraBssPpdu(psdu, txVector))
2092 NS_LOG_DEBUG(
"PPDU not classified as intra-BSS, update the basic NAV");
2093 VhtFrameExchangeManager::UpdateNav(psdu, txVector);
2097 NS_LOG_DEBUG(
"PPDU classified as intra-BSS, update the intra-BSS NAV");
2098 Time duration = psdu->GetDuration();
2101 if (psdu->GetHeader(0).IsCfEnd())
2107 NS_LOG_DEBUG(
"Received CF-End, resetting the intra-BSS NAV");
2108 IntraBssNavResetTimeout();
2114 auto intraBssNavEnd = Simulator::Now() + duration;
2115 if (intraBssNavEnd > m_intraBssNavEnd)
2117 m_intraBssNavEnd = intraBssNavEnd;
2118 NS_LOG_DEBUG(
"Updated intra-BSS NAV=" << m_intraBssNavEnd);
2129 if (psdu->GetHeader(0).IsRts())
2132 GetWifiRemoteStationManager()->GetCtsTxVector(psdu->GetAddr2(), txVector.
GetMode());
2133 auto navResetDelay =
2134 2 * m_phy->GetSifs() +
2135 WifiPhy::CalculateTxDuration(
GetCtsSize(), ctsTxVector, m_phy->GetPhyBand()) +
2136 WifiPhy::CalculatePhyPreambleAndHeaderDuration(ctsTxVector) + 2 * m_phy->GetSlot();
2137 m_intraBssNavResetEvent =
2138 Simulator::Schedule(navResetDelay,
2139 &HeFrameExchangeManager::IntraBssNavResetTimeout,
2143 NS_LOG_DEBUG(
"Current intra-BSS NAV=" << m_intraBssNavEnd);
2145 m_channelAccessManager->NotifyNavStartNow(duration);
2149HeFrameExchangeManager::ClearTxopHolderIfNeeded()
2152 if (m_intraBssNavEnd <= Simulator::Now())
2154 m_txopHolder.reset();
2159HeFrameExchangeManager::NavResetTimeout()
2162 m_navEnd = Simulator::Now();
2165 Time intraBssNav = Simulator::GetDelayLeft(m_intraBssNavResetEvent);
2166 m_channelAccessManager->NotifyNavResetNow(intraBssNav);
2170HeFrameExchangeManager::IntraBssNavResetTimeout()
2173 m_intraBssNavEnd = Simulator::Now();
2174 ClearTxopHolderIfNeeded();
2176 Time basicNav = Simulator::GetDelayLeft(m_navResetEvent);
2177 m_channelAccessManager->NotifyNavResetNow(basicNav);
2180std::optional<Mac48Address>
2191 return VhtFrameExchangeManager::FindTxopHolder(hdr, txVector);
2193 return std::nullopt;
2197HeFrameExchangeManager::VirtualCsMediumIdle()
const
2202 return m_navEnd <= Simulator::Now() && m_intraBssNavEnd <= Simulator::Now();
2218 const Time now = Simulator::Now();
2225 NS_ASSERT_MSG(m_staMac,
"UL MU CS is only performed by non-AP STAs");
2228 "No User Info field for STA (" << m_self
2229 <<
") AID=" << m_staMac->GetAssociationId());
2231 std::set<uint8_t> indices;
2235 auto ctsTxVector = GetCtsTxVectorAfterMuRts(trigger, m_staMac->GetAssociationId());
2236 auto bw = ctsTxVector.GetChannelWidth();
2237 indices = m_phy->GetOperatingChannel().GetAll20MHzChannelIndicesInPrimary(bw);
2242 m_phy->GetOperatingChannel().Get20MHzIndicesCoveringRu(userInfoIt->GetRuAllocation(),
2245 return !m_channelAccessManager->GetPer20MHzBusy(indices);
2254 NS_LOG_FUNCTION(
this << *mpdu << rxSignalInfo << txVector << inAmpdu);
2257 NS_ASSERT(mpdu->GetHeader().GetAddr1().IsGroup() || mpdu->GetHeader().GetAddr1() == m_self);
2261 if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
2262 m_txTimer.GetReason() == WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF)
2265 NS_ASSERT(m_txParams.m_acknowledgment &&
2266 m_txParams.m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
2267 auto acknowledgment =
static_cast<WifiUlMuMultiStaBa*
>(m_txParams.m_acknowledgment.get());
2270 if (!m_txTimer.GetStasExpectedToRespond().contains(sender))
2272 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2278 NS_LOG_DEBUG(
"Received a BlockAckReq in a TB PPDU from " << sender);
2281 mpdu->GetPacket()->PeekHeader(blockAckReq);
2284 GetBaManager(tid)->NotifyGotBlockAckRequest(
2285 m_mac->GetMldAddress(sender).value_or(sender),
2290 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, tid), index);
2291 acknowledgment->baType.m_bitmapLen.push_back(
2292 m_mac->GetBaTypeAsRecipient(sender, tid).m_bitmapLen.at(0));
2294 m_muSnrTag.Set(staId, rxSignalInfo.
snr);
2298 NS_LOG_DEBUG(
"Received an S-MPDU in a TB PPDU from " << sender <<
" (" << *mpdu <<
")");
2301 GetBaManager(tid)->NotifyGotMpdu(mpdu);
2304 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, tid), index);
2305 acknowledgment->baType.m_bitmapLen.push_back(0);
2307 m_muSnrTag.Set(staId, rxSignalInfo.
snr);
2316 VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
2321 if (!acknowledgment->stationsReceivingMultiStaBa.empty() && !m_multiStaBaEvent.IsPending())
2323 m_multiStaBaEvent = Simulator::Schedule(m_phy->GetSifs(),
2324 &HeFrameExchangeManager::SendMultiStaBlockAck,
2326 std::cref(m_txParams),
2327 mpdu->GetHeader().GetDuration());
2331 m_txTimer.GotResponseFrom(sender);
2333 if (m_txTimer.GetStasExpectedToRespond().empty())
2337 m_channelAccessManager->NotifyAckTimeoutResetNow();
2339 if (!m_multiStaBaEvent.IsPending())
2344 m_edca->ResetCw(m_linkId);
2345 TransmissionSucceeded();
2353 if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
2354 m_txTimer.GetReason() == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF &&
2357 const auto& sender = hdr.
GetAddr2();
2359 if (!m_txTimer.GetStasExpectedToRespond().contains(sender))
2361 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2366 NS_LOG_WARN(
"No QoS Null frame in the received MPDU");
2370 NS_LOG_DEBUG(
"Received a QoS Null frame in a TB PPDU from " << sender);
2371 ReceivedQosNullAfterBsrpTf(sender);
2379 if (hdr.
IsCts() && m_txTimer.IsRunning() &&
2380 m_txTimer.GetReason() == WifiTxTimer::WAIT_CTS && m_psduMap.size() == 1)
2385 Mac48Address sender = m_psduMap.begin()->second->GetAddr1();
2389 mpdu->GetPacket()->PeekPacketTag(tag);
2390 GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
2391 GetWifiRemoteStationManager()->ReportRtsOk(m_psduMap.begin()->second->GetHeader(0),
2397 m_channelAccessManager->NotifyCtsTimeoutResetNow();
2398 ProtectionCompleted();
2400 else if (hdr.
IsCts() && m_txTimer.IsRunning() &&
2401 m_txTimer.GetReason() == WifiTxTimer::WAIT_CTS_AFTER_MU_RTS)
2406 NS_LOG_DEBUG(
"Received a CTS frame in response to an MU-RTS");
2409 m_channelAccessManager->NotifyCtsTimeoutResetNow();
2410 ProtectionCompleted();
2412 else if (hdr.
IsAck() && m_txTimer.IsRunning() &&
2413 m_txTimer.GetReason() == WifiTxTimer::WAIT_NORMAL_ACK_AFTER_DL_MU_PPDU)
2417 NS_ASSERT(m_txParams.m_acknowledgment->method ==
2418 WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE);
2420 auto acknowledgment =
2422 NS_ASSERT(acknowledgment->stationsReplyingWithNormalAck.size() == 1);
2424 uint16_t staId = m_apMac->GetAssociationId(
2425 acknowledgment->stationsReplyingWithNormalAck.begin()->first,
2427 auto it = m_psduMap.find(staId);
2430 acknowledgment->stationsReplyingWithNormalAck.begin()->first);
2432 mpdu->GetPacket()->PeekPacketTag(tag);
2433 ReceivedNormalAck(*it->second->begin(),
2434 m_txParams.m_txVector,
2447 m_txTimer.GetReason() == WifiTxTimer::WAIT_BLOCK_ACKS_IN_TB_PPDU)
2450 NS_LOG_DEBUG(
"Received BlockAck in TB PPDU from=" << sender);
2453 mpdu->GetPacket()->PeekPacketTag(tag);
2457 mpdu->GetPacket()->PeekHeader(blockAck);
2459 std::pair<uint16_t, uint16_t> ret =
2460 GetBaManager(tid)->NotifyGotBlockAck(m_linkId,
2462 m_mac->GetMldAddress(sender).value_or(sender),
2464 GetWifiRemoteStationManager()->ReportAmpduTxStatus(sender,
2469 m_txParams.m_txVector);
2472 if (!m_txTimer.GetStasExpectedToRespond().contains(sender))
2474 NS_LOG_WARN(
"Received a BlockAck from an unexpected stations: " << sender);
2478 m_txTimer.GotResponseFrom(sender);
2480 if (m_txTimer.GetStasExpectedToRespond().empty())
2484 m_channelAccessManager->NotifyAckTimeoutResetNow();
2488 m_triggerFrame =
nullptr;
2491 m_edca->ResetCw(m_linkId);
2493 TransmissionSucceeded();
2496 else if (hdr.
IsBlockAck() && m_txTimer.IsRunning() &&
2497 m_txTimer.GetReason() == WifiTxTimer::WAIT_BLOCK_ACK_AFTER_TB_PPDU)
2500 mpdu->GetPacket()->PeekHeader(blockAck);
2503 "A Multi-STA BlockAck is expected after a TB PPDU");
2505 m_txTimer.GotResponseFrom(hdr.
GetAddr2());
2507 NS_ASSERT(m_staMac && m_staMac->IsAssociated());
2510 NS_LOG_DEBUG(
"The sender is not the AP we are associated with");
2514 uint16_t staId = m_staMac->GetAssociationId();
2517 if (indices.empty())
2519 NS_LOG_DEBUG(
"No Per AID TID Info subfield intended for me");
2524 mpdu->GetPacket()->PeekPacketTag(tag);
2527 for (
const auto& index : indices)
2534 NS_ABORT_IF(m_psduMap.empty() || m_psduMap.begin()->first != staId);
2535 GetBaManager(tid)->NotifyGotAck(m_linkId, *m_psduMap.at(staId)->begin());
2544 NS_ABORT_IF(m_psduMap.empty() || m_psduMap.begin()->first != staId);
2545 std::set<uint8_t> tids = m_psduMap.at(staId)->GetTids();
2546 NS_ABORT_MSG_IF(tids.size() > 1,
"Multi-TID A-MPDUs not supported yet");
2547 tid = *tids.begin();
2550 std::pair<uint16_t, uint16_t> ret = GetBaManager(tid)->NotifyGotBlockAck(
2556 GetWifiRemoteStationManager()->ReportAmpduTxStatus(hdr.
GetAddr2(),
2561 m_txParams.m_txVector);
2564 if (m_psduMap.at(staId)->GetHeader(0).IsQosData() &&
2566 || std::any_of(blockAck.
GetBitmap(index).begin(),
2568 [](uint8_t b) { return b != 0; })))
2570 NS_ASSERT(m_psduMap.at(staId)->GetHeader(0).HasData());
2571 NS_ASSERT(m_psduMap.at(staId)->GetHeader(0).GetQosTid() == tid);
2576 m_mac->GetQosTxop(tid)->StartMuEdcaTimerNow(m_linkId);
2582 m_channelAccessManager->NotifyAckTimeoutResetNow();
2584 for (
const auto& [staId, psdu] : m_psduMap)
2586 if (psdu->GetNMpdus() == 1 && psdu->GetHeader(0).IsBlockAckReq())
2593 else if (hdr.
IsBlockAck() && m_txTimer.IsRunning() &&
2594 m_txTimer.GetReason() == WifiTxTimer::WAIT_BLOCK_ACK)
2600 VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
2613 m_triggerFrameInAmpdu =
true;
2618 mpdu->GetPacket()->PeekHeader(trigger);
2629 uint16_t staId = m_staMac->GetAssociationId();
2634 NS_LOG_DEBUG(
"Received MU-RTS Trigger Frame from=" << sender);
2635 GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
2645 m_sendCtsEvent = Simulator::Schedule(m_phy->GetSifs(),
2646 &HeFrameExchangeManager::SendCtsAfterMuRts,
2655 NS_LOG_DEBUG(
"Received MU-BAR Trigger Frame from=" << sender);
2656 GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
2664 GetBaManager(tid)->NotifyGotBlockAckRequest(
2665 m_mac->GetMldAddress(sender).value_or(sender),
2669 Simulator::Schedule(m_phy->GetSifs(),
2670 &HeFrameExchangeManager::ReceiveMuBarTrigger,
2679 Simulator::Schedule(m_phy->GetSifs(),
2680 &HeFrameExchangeManager::ReceiveBasicTrigger,
2685 else if (trigger.
IsBsrp())
2687 Simulator::Schedule(m_phy->GetSifs(),
2688 &HeFrameExchangeManager::SendQosNullFramesInTbPpdu,
2697 VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
2705 VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
2713 const std::vector<bool>& perMpduStatus)
2715 std::set<uint8_t> tids = psdu->GetTids();
2717 if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
2718 m_txTimer.GetReason() == WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF)
2721 NS_ASSERT(m_txParams.m_acknowledgment &&
2722 m_txParams.m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
2723 auto acknowledgment =
static_cast<WifiUlMuMultiStaBa*
>(m_txParams.m_acknowledgment.get());
2726 if (!m_txTimer.GetStasExpectedToRespond().contains(sender))
2728 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2732 NS_LOG_DEBUG(
"Received an A-MPDU in a TB PPDU from " << sender <<
" (" << *psdu <<
")");
2734 if (std::any_of(tids.begin(), tids.end(), [&psdu](uint8_t tid) {
2735 return psdu->GetAckPolicyForTid(tid) == WifiMacHeader::NORMAL_ACK;
2738 if (std::all_of(perMpduStatus.cbegin(), perMpduStatus.cend(), [](
bool v) { return v; }))
2741 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, 14),
2743 acknowledgment->baType.m_bitmapLen.push_back(0);
2749 for (
const auto& tid : tids)
2751 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, tid),
2753 acknowledgment->baType.m_bitmapLen.push_back(
2754 m_mac->GetBaTypeAsRecipient(sender, tid).m_bitmapLen.at(0));
2758 m_muSnrTag.Set(staId, rxSignalInfo.
snr);
2762 if (!acknowledgment->stationsReceivingMultiStaBa.empty() && !m_multiStaBaEvent.IsPending())
2764 m_multiStaBaEvent = Simulator::Schedule(m_phy->GetSifs(),
2765 &HeFrameExchangeManager::SendMultiStaBlockAck,
2767 std::cref(m_txParams),
2768 psdu->GetDuration());
2772 m_txTimer.GotResponseFrom(sender);
2774 if (m_txTimer.GetStasExpectedToRespond().empty())
2778 m_channelAccessManager->NotifyAckTimeoutResetNow();
2780 if (!m_multiStaBaEvent.IsPending())
2785 m_edca->ResetCw(m_linkId);
2786 TransmissionSucceeded();
2794 if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
2795 m_txTimer.GetReason() == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF)
2799 if (!m_txTimer.GetStasExpectedToRespond().contains(sender))
2801 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2804 if (std::none_of(psdu->begin(), psdu->end(), [](
Ptr<WifiMpdu> mpdu) {
2805 return mpdu->GetHeader().IsQosData() && !mpdu->GetHeader().HasData();
2808 NS_LOG_WARN(
"No QoS Null frame in the received PSDU");
2812 NS_LOG_DEBUG(
"Received QoS Null frames in a TB PPDU from " << sender);
2813 ReceivedQosNullAfterBsrpTf(sender);
2819 if (m_triggerFrameInAmpdu)
2822 auto psduIt = psdu->begin();
2823 while (psduIt != psdu->end())
2825 if ((*psduIt)->GetHeader().IsTrigger())
2827 ReceiveMpdu(*psduIt, rxSignalInfo, txVector,
false);
2832 m_triggerFrameInAmpdu =
false;
2837 VhtFrameExchangeManager::EndReceiveAmpdu(psdu, rxSignalInfo, txVector, perMpduStatus);
2846 m_txTimer.GetReason() == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF);
2849 m_txTimer.GotResponseFrom(sender);
2851 if (m_txTimer.GetStasExpectedToRespond().empty())
2854 m_channelAccessManager->NotifyAckTimeoutResetNow();
2858 m_edca->ResetCw(m_linkId);
2859 TransmissionSucceeded();
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.
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...
#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.
Ptr< const AttributeChecker > MakeBooleanChecker()
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.
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
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.