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)
131 "A Multi-User Scheduler can only be aggregated to an HE AP");
152 (!(mpdu = edca->PeekNextMpdu(
m_linkId)) ||
153 (mpdu->GetHeader().IsQosData() && !mpdu->GetHeader().GetAddr1().IsGroup() &&
154 m_mac->GetBaAgreementEstablishedAsOriginator(mpdu->GetHeader().GetAddr1(),
155 mpdu->GetHeader().GetQosTid()))))
174 "The Multi-user Scheduler returned DL_MU_TX with empty psduMap, do not transmit");
225 <<
") incompatible with Basic Trigger Frame");
229 <<
") incompatible with BSRP Trigger Frame");
231 auto txVector = trigger.GetHeTbTxVector(trigger.begin()->GetAid12());
248 if (mpdu->IsQueued())
265 "Cannot use RTS/CTS with MU PPDUs");
282std::set<Mac48Address>
285 std::set<Mac48Address> recipients;
289 for (
const auto& userInfo : trigger)
291 const auto addressIt = aidAddrMap.find(userInfo.GetAid12());
292 NS_ASSERT_MSG(addressIt != aidAddrMap.end(),
"AID not found");
293 recipients.insert(addressIt->second);
313 NS_LOG_INFO(
"Multi-user scheduler aborted the transmission");
344 NS_LOG_FUNCTION(
this << muRtsSize << muRtsTxVector << txDuration << response);
379 protection->muRts.SetCsRequired(
true);
381 payload->AddHeader(protection->muRts);
387 mpdu->GetHeader().SetDuration(
389 protection->muRtsTxVector,
402 protection->muRtsTxVector,
414 protection->muRtsTxVector);
447 if (mpdu->IsQueued())
454 if (
const auto& hdr =
m_psduMap.cbegin()->second->GetHeader(0); !hdr.GetAddr1().IsGroup())
459 for (
const auto& [staId, psdu] :
m_psduMap)
461 if (psdu->GetAddr1().IsGroup())
483 auto it = std::find_if(
486 [&to](std::pair<uint16_t,
Ptr<WifiPsdu>> psdu) { return psdu.second->GetAddr1() == to; });
487 if (it != psduMap.end())
522 NS_LOG_DEBUG(address <<
" did not respond, hence it is no longer protected");
532 NS_LOG_DEBUG(
"Schedule another transmission in a SIFS after successful BSRP TF");
535 if (!StartTransmission(m_edca, Seconds(0)))
553HeFrameExchangeManager::SendPsduMap()
565 std::set<Mac48Address> staExpectResponseFrom;
572 if (m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE)
574 auto acknowledgment =
578 for (
const auto& psdu : m_psduMap)
580 if (acknowledgment->stationsSendBlockAckReqTo.contains(psdu.second->GetAddr1()))
583 std::set<uint8_t> tids = psdu.second->GetTids();
585 "Acknowledgment method incompatible with a Multi-TID A-MPDU");
586 uint8_t tid = *tids.begin();
590 m_mac->GetQosTxop(tid)->PrepareBlockAckRequest(psdu.second->GetAddr1(), tid);
591 m_edca->GetBaManager()->ScheduleBar(reqHdr, hdr);
595 if (!acknowledgment->stationsReplyingWithNormalAck.empty())
598 timerType = WifiTxTimer::WAIT_NORMAL_ACK_AFTER_DL_MU_PPDU;
600 &acknowledgment->stationsReplyingWithNormalAck.begin()->second.ackTxVector;
601 auto from = acknowledgment->stationsReplyingWithNormalAck.begin()->first;
602 psdu = GetPsduTo(from, m_psduMap);
604 mpdu = *psdu->begin();
605 staExpectResponseFrom.insert(from);
607 else if (!acknowledgment->stationsReplyingWithBlockAck.empty())
610 timerType = WifiTxTimer::WAIT_BLOCK_ACK;
612 &acknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
613 auto from = acknowledgment->stationsReplyingWithBlockAck.begin()->first;
614 psdu = GetPsduTo(from, m_psduMap);
615 staExpectResponseFrom.insert(from);
622 else if (m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_TF_MU_BAR)
624 auto acknowledgment =
static_cast<WifiDlMuTfMuBar*
>(m_txParams.m_acknowledgment.get());
631 std::map<uint16_t, CtrlBAckRequestHeader> recipients;
633 NS_ASSERT(!acknowledgment->stationsReplyingWithBlockAck.empty());
634 auto staIt = acknowledgment->stationsReplyingWithBlockAck.begin();
635 m_trigVector = staIt->second.blockAckTxVector;
636 while (staIt != acknowledgment->stationsReplyingWithBlockAck.end())
639 uint16_t staId = m_apMac->GetAssociationId(staIt->first, m_linkId);
641 m_trigVector.SetHeMuUserInfo(staId,
642 staIt->second.blockAckTxVector.GetHeMuUserInfo(staId));
643 recipients.emplace(staId, staIt->second.barHeader);
649 m_trigVector.SetLength(acknowledgment->ulLength);
651 m_triggerFrame = PrepareMuBar(m_trigVector, recipients);
658 for (
auto& station : acknowledgment->stationsReplyingWithBlockAck)
660 staExpectResponseFrom.insert(station.first);
663 Ptr<WifiPsdu> triggerPsdu = GetWifiPsdu(m_triggerFrame, acknowledgment->muBarTxVector);
664 Time txDuration = WifiPhy::CalculateTxDuration(triggerPsdu->GetSize(),
665 acknowledgment->muBarTxVector,
666 m_phy->GetPhyBand());
668 *acknowledgment->acknowledgmentTime -= (m_phy->GetSifs() + txDuration);
669 m_triggerFrame->GetHeader().SetDuration(GetPsduDurationId(txDuration, m_txParams));
672 &acknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
673 Time timeout = txDuration + m_phy->GetSifs() + m_phy->GetSlot() +
674 m_phy->CalculatePhyPreambleAndHeaderDuration(*responseTxVector);
676 m_txTimer.Set(WifiTxTimer::WAIT_BLOCK_ACKS_IN_TB_PPDU,
678 staExpectResponseFrom,
679 &HeFrameExchangeManager::BlockAcksInTbPpduTimeout,
682 staExpectResponseFrom.size());
683 m_channelAccessManager->NotifyAckTimeoutStartNow(
timeout);
685 ForwardPsduDown(triggerPsdu, acknowledgment->muBarTxVector);
690 hePhy->SetTrigVector(m_trigVector,
timeout);
698 else if (m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF)
700 auto acknowledgment =
static_cast<WifiDlMuAggregateTf*
>(m_txParams.m_acknowledgment.get());
706 for (
auto& station : acknowledgment->stationsReplyingWithBlockAck)
708 staExpectResponseFrom.insert(station.first);
711 auto psduMapIt = std::find_if(m_psduMap.begin(),
714 return psdu.second->GetAddr1() == station.first;
719 std::vector<Ptr<WifiMpdu>> mpduList(psduMapIt->second->begin(),
720 psduMapIt->second->end());
721 NS_ASSERT(mpduList.size() == psduMapIt->second->GetNMpdus());
724 station.second.blockAckTxVector.SetLength(acknowledgment->ulLength);
725 mpduList.push_back(PrepareMuBar(station.second.blockAckTxVector,
726 {{psduMapIt->first, station.second.barHeader}}));
727 psduMapIt->second = Create<WifiPsdu>(std::move(mpduList));
728 m_trigVector.SetHeMuUserInfo(
730 station.second.blockAckTxVector.GetHeMuUserInfo(psduMapIt->first));
733 timerType = WifiTxTimer::WAIT_BLOCK_ACKS_IN_TB_PPDU;
735 &acknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
736 m_trigVector.
SetLength(acknowledgment->ulLength);
741 else if (m_txParams.m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA)
745 mpdu = *m_psduMap.begin()->second->begin();
747 auto acknowledgment =
static_cast<WifiUlMuMultiStaBa*
>(m_txParams.m_acknowledgment.get());
750 for (
const auto& station : acknowledgment->stationsReceivingMultiStaBa)
752 staExpectResponseFrom.insert(station.first.first);
758 acknowledgment->baType.m_bitmapLen.clear();
760 timerType = WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF;
761 responseTxVector = &acknowledgment->tbPpduTxVector;
762 m_trigVector = GetTrigVector(m_muScheduler->GetUlMuInfo(m_linkId).trigger);
767 else if (m_txParams.m_acknowledgment->method == WifiAcknowledgment::NONE &&
768 !m_txParams.m_txVector.IsUlMu() &&
IsTrigger(m_psduMap))
770 CtrlTriggerHeader& trigger = m_muScheduler->GetUlMuInfo(m_linkId).trigger;
775 for (
const auto& userInfo : trigger)
777 auto staIt = m_apMac->GetStaList(m_linkId).find(userInfo.GetAid12());
778 NS_ASSERT(staIt != m_apMac->GetStaList(m_linkId).end());
779 staExpectResponseFrom.insert(staIt->second);
782 timerType = WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF;
783 txVector = trigger.GetHeTbTxVector(trigger.begin()->GetAid12());
784 responseTxVector = &txVector;
785 m_trigVector = GetTrigVector(m_muScheduler->GetUlMuInfo(m_linkId).trigger);
790 else if (m_txParams.m_txVector.IsUlMu() &&
791 m_txParams.m_acknowledgment->method == WifiAcknowledgment::ACK_AFTER_TB_PPDU)
794 timerType = WifiTxTimer::WAIT_BLOCK_ACK_AFTER_TB_PPDU;
795 NS_ASSERT(m_staMac && m_staMac->IsAssociated());
796 auto recv = m_psduMap.begin()->second->GetAddr1();
797 txVector = GetWifiRemoteStationManager()->GetBlockAckTxVector(recv, m_txParams.m_txVector);
798 responseTxVector = &txVector;
799 staExpectResponseFrom.insert(recv);
804 else if (m_txParams.m_txVector.IsUlMu() &&
805 m_txParams.m_acknowledgment->method == WifiAcknowledgment::NONE)
811 NS_ABORT_MSG(
"Unable to handle the selected acknowledgment method ("
812 << m_txParams.m_acknowledgment.get() <<
")");
817 for (
const auto& psdu : m_psduMap)
819 psduMap.emplace(psdu.first, psdu.second);
823 if (m_txParams.m_txVector.IsUlMu())
825 txDuration = HePhy::ConvertLSigLengthToHeTbPpduDuration(m_txParams.m_txVector.GetLength(),
826 m_txParams.m_txVector,
827 m_phy->GetPhyBand());
832 WifiPhy::CalculateTxDuration(psduMap, m_txParams.m_txVector, m_phy->GetPhyBand());
835 Time durationId = GetPsduDurationId(txDuration, m_txParams);
837 if (m_continueTxopAfterBsrpTf && m_edca && m_edca->GetTxopLimit(m_linkId).IsZero() &&
838 timerType == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF)
842 durationId += m_muScheduler->GetExtraTimeForBsrpTfDurationId(m_linkId);
845 for (
auto& psdu : m_psduMap)
847 psdu.second->SetDuration(durationId);
851 if (timerType == WifiTxTimer::NOT_RUNNING)
856 Simulator::Schedule(txDuration + m_phy->GetSifs(),
857 &HeFrameExchangeManager::SendPsduMap,
860 else if (!m_txParams.m_txVector.IsUlMu())
862 Simulator::Schedule(txDuration, &HeFrameExchangeManager::TransmissionSucceeded,
this);
867 Time timeout = txDuration + m_phy->GetSifs() + m_phy->GetSlot() +
868 m_phy->CalculatePhyPreambleAndHeaderDuration(*responseTxVector);
869 m_channelAccessManager->NotifyAckTimeoutStartNow(
timeout);
874 case WifiTxTimer::WAIT_NORMAL_ACK_AFTER_DL_MU_PPDU:
876 m_txTimer.Set(timerType,
878 staExpectResponseFrom,
879 &HeFrameExchangeManager::NormalAckTimeout,
882 m_txParams.m_txVector);
884 case WifiTxTimer::WAIT_BLOCK_ACK:
886 m_txTimer.Set(timerType,
888 staExpectResponseFrom,
889 &HeFrameExchangeManager::BlockAckTimeout,
892 m_txParams.m_txVector);
894 case WifiTxTimer::WAIT_BLOCK_ACKS_IN_TB_PPDU:
895 m_txTimer.Set(timerType,
897 staExpectResponseFrom,
898 &HeFrameExchangeManager::BlockAcksInTbPpduTimeout,
901 staExpectResponseFrom.size());
903 case WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF:
904 case WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF:
905 m_txTimer.Set(timerType,
907 staExpectResponseFrom,
908 &HeFrameExchangeManager::TbPpduTimeout,
911 staExpectResponseFrom.size());
913 case WifiTxTimer::WAIT_BLOCK_ACK_AFTER_TB_PPDU:
914 m_txTimer.Set(timerType,
916 staExpectResponseFrom,
917 &HeFrameExchangeManager::BlockAckAfterTbPpduTimeout,
919 m_psduMap.begin()->second,
920 m_txParams.m_txVector);
929 ForwardPsduMapDown(psduMap, m_txParams.m_txVector);
931 if (timerType == WifiTxTimer::WAIT_BLOCK_ACKS_IN_TB_PPDU ||
932 timerType == WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF ||
933 timerType == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF)
936 auto hePhy = StaticCast<HePhy>(m_phy->GetPhyEntity(responseTxVector->GetModulationClass()));
937 hePhy->SetTrigVector(m_trigVector, m_txTimer.GetDelayLeft());
939 else if (timerType == WifiTxTimer::NOT_RUNNING && m_txParams.m_txVector.IsUlMu())
942 Simulator::Schedule(txDuration, &WifiPsduMap::clear, &m_psduMap);
945 if (m_txTimer.IsRunning() && timerType != WifiTxTimer::WAIT_BLOCK_ACK_AFTER_TB_PPDU)
951 for (
const auto& address : staExpectResponseFrom)
953 if (!GetWifiRemoteStationManager()->GetEmlsrEnabled(address) ||
954 timerType == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF ||
955 m_protectedStas.contains(address))
957 m_sentFrameTo.insert(address);
971 auto sigBMode = hePhy->GetSigBMode(txVector);
975 for (
const auto& psdu : psduMap)
977 NS_LOG_DEBUG(
"Transmitting: [STAID=" << psdu.first <<
", " << *psdu.second <<
"]");
980 for (
const auto& [staId, psdu] : psduMap)
982 FinalizeMacHeader(psdu);
983 NotifyTxToEdca(psdu);
987 if (psduMap.size() > 1 || psduMap.begin()->second->IsAggregate() ||
988 psduMap.begin()->second->IsSingle())
993 auto txDuration = WifiPhy::CalculateTxDuration(psduMap, txVector, m_phy->GetPhyBand());
997 m_txNav =
Max(m_txNav, Simulator::Now() + txDuration + psduMap.cbegin()->second->GetDuration());
999 m_phy->Send(psduMap, txVector);
1004 std::map<uint16_t, CtrlBAckRequestHeader> recipients)
const
1011 SetTargetRssi(muBar);
1017 for (
auto& userInfo : muBar)
1019 auto recipientIt = recipients.find(userInfo.GetAid12());
1020 NS_ASSERT(recipientIt != recipients.end());
1023 userInfo.SetMuBarTriggerDepUserInfo(recipientIt->second);
1027 bar->AddHeader(muBar);
1035 rxAddress = Mac48Address::GetBroadcast();
1040 rxAddress = m_apMac->GetStaList(m_linkId).at(recipients.begin()->first);
1052 return Create<WifiMpdu>(bar, hdr);
1061 if (protection->
method == WifiProtection::MU_RTS_CTS)
1068 GetCtsTxVectorAfterMuRts(muRtsCtsProtection->muRts,
1069 muRtsCtsProtection->muRts.begin()->GetAid12());
1072 muRtsCtsProtection->muRts.GetSerializedSize() + WIFI_MAC_FCS_LENGTH;
1073 muRtsCtsProtection->protectionTime =
1074 WifiPhy::CalculateTxDuration(muRtsSize,
1075 muRtsCtsProtection->muRtsTxVector,
1076 m_phy->GetPhyBand()) +
1077 WifiPhy::CalculateTxDuration(
GetCtsSize(), ctsTxVector, m_phy->GetPhyBand()) +
1078 2 * m_phy->GetSifs();
1082 VhtFrameExchangeManager::CalculateProtectionTime(protection);
1095 if (acknowledgment->
method == WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE)
1102 NS_ABORT_IF(dlMuBarBaAcknowledgment->stationsReplyingWithNormalAck.size() +
1103 dlMuBarBaAcknowledgment->stationsReplyingWithBlockAck.size() >
1106 if (!dlMuBarBaAcknowledgment->stationsReplyingWithNormalAck.empty())
1109 dlMuBarBaAcknowledgment->stationsReplyingWithNormalAck.begin()->second;
1112 WifiPhy::CalculateTxDuration(
GetAckSize(), info.ackTxVector, m_phy->GetPhyBand());
1115 if (!dlMuBarBaAcknowledgment->stationsReplyingWithBlockAck.empty())
1118 dlMuBarBaAcknowledgment->stationsReplyingWithBlockAck.begin()->second;
1120 m_phy->GetSifs() + WifiPhy::CalculateTxDuration(
GetBlockAckSize(info.baType),
1121 info.blockAckTxVector,
1122 m_phy->GetPhyBand());
1125 for (
const auto& stations : dlMuBarBaAcknowledgment->stationsSendBlockAckReqTo)
1127 const auto& info = stations.second;
1128 duration += m_phy->GetSifs() +
1130 info.blockAckReqTxVector,
1131 m_phy->GetPhyBand()) +
1134 info.blockAckTxVector,
1135 m_phy->GetPhyBand());
1138 dlMuBarBaAcknowledgment->acknowledgmentTime = duration;
1143 else if (acknowledgment->
method == WifiAcknowledgment::DL_MU_TF_MU_BAR)
1145 auto dlMuTfMuBarAcknowledgment =
static_cast<WifiDlMuTfMuBar*
>(acknowledgment);
1149 for (
const auto& stations : dlMuTfMuBarAcknowledgment->stationsReplyingWithBlockAck)
1152 const auto& info = stations.second;
1153 NS_ASSERT(info.blockAckTxVector.GetHeMuUserInfoMap().size() == 1);
1154 uint16_t staId = info.blockAckTxVector.GetHeMuUserInfoMap().begin()->first;
1156 info.blockAckTxVector,
1157 m_phy->GetPhyBand(),
1160 if (currBlockAckDuration > duration)
1162 duration = currBlockAckDuration;
1168 WifiTxVector& txVector = dlMuTfMuBarAcknowledgment->stationsReplyingWithBlockAck.begin()
1169 ->second.blockAckTxVector;
1170 std::tie(dlMuTfMuBarAcknowledgment->ulLength, duration) =
1171 HePhy::ConvertHeTbPpduDurationToLSigLength(duration, txVector, m_phy->GetPhyBand());
1174 if (dlMuTfMuBarAcknowledgment->muBarTxVector.GetModulationClass() >=
WIFI_MOD_CLASS_VHT)
1177 muBarSize = MpduAggregator::GetSizeIfAggregated(muBarSize, 0);
1179 dlMuTfMuBarAcknowledgment->acknowledgmentTime =
1181 WifiPhy::CalculateTxDuration(muBarSize,
1182 dlMuTfMuBarAcknowledgment->muBarTxVector,
1183 m_phy->GetPhyBand()) +
1184 m_phy->GetSifs() + duration;
1189 else if (acknowledgment->
method == WifiAcknowledgment::DL_MU_AGGREGATE_TF)
1195 for (
const auto& stations : dlMuAggrTfAcknowledgment->stationsReplyingWithBlockAck)
1198 const auto& info = stations.second;
1199 NS_ASSERT(info.blockAckTxVector.GetHeMuUserInfoMap().size() == 1);
1200 uint16_t staId = info.blockAckTxVector.GetHeMuUserInfoMap().begin()->first;
1202 info.blockAckTxVector,
1203 m_phy->GetPhyBand(),
1206 if (currBlockAckDuration > duration)
1208 duration = currBlockAckDuration;
1215 dlMuAggrTfAcknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
1216 std::tie(dlMuAggrTfAcknowledgment->ulLength, duration) =
1217 HePhy::ConvertHeTbPpduDurationToLSigLength(duration, txVector, m_phy->GetPhyBand());
1218 dlMuAggrTfAcknowledgment->acknowledgmentTime = m_phy->GetSifs() + duration;
1223 else if (acknowledgment->
method == WifiAcknowledgment::UL_MU_MULTI_STA_BA)
1228 ulMuMultiStaBa->multiStaBaTxVector,
1229 m_phy->GetPhyBand());
1230 ulMuMultiStaBa->acknowledgmentTime = m_phy->GetSifs() + duration;
1235 else if (acknowledgment->
method == WifiAcknowledgment::ACK_AFTER_TB_PPDU)
1244 VhtFrameExchangeManager::CalculateAcknowledgmentTime(acknowledgment);
1249HeFrameExchangeManager::GetCtsModeAfterMuRts()
const
1254 : OfdmPhy::GetOfdmRate6Mbps();
1259 uint16_t staId)
const
1264 NS_ASSERT_MSG(userInfoIt != trigger.
end(),
"User Info field for AID=" << staId <<
" not found");
1267 if (uint8_t ru = userInfoIt->GetMuRtsRuAllocation(); ru < 65)
1285 auto txVector = GetWifiRemoteStationManager()->GetCtsTxVector(m_bssid, GetCtsModeAfterMuRts());
1287 txVector.SetChannelWidth(bw);
1293HeFrameExchangeManager::GetTxDuration(
uint32_t ppduPayloadSize,
1299 return VhtFrameExchangeManager::GetTxDuration(ppduPayloadSize, receiver, txParams);
1306 txParams.
m_acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF)
1310 NS_ASSERT_MSG(psduInfo,
"No information for " << receiver <<
" in TX params");
1311 NS_ASSERT_MSG(!psduInfo->seqNumbers.empty(),
"No sequence number for " << receiver);
1312 const auto tid = psduInfo->seqNumbers.cbegin()->first;
1314 ppduPayloadSize = MpduAggregator::GetSizeIfAggregated(
1315 GetMuBarSize({m_mac->GetBarTypeAsOriginator(receiver, tid)}),
1319 uint16_t staId = (txParams.
m_txVector.
IsDlMu() ? m_apMac->GetAssociationId(receiver, m_linkId)
1320 : m_staMac->GetAssociationId());
1321 Time psduDuration = WifiPhy::CalculateTxDuration(ppduPayloadSize,
1323 m_phy->GetPhyBand(),
1330HeFrameExchangeManager::TbPpduTimeout(
WifiPsduMap* psduMap, std::size_t nSolicitedStations)
1333 DoTbPpduTimeout(psduMap, nSolicitedStations,
true);
1338 std::size_t nSolicitedStations,
1339 bool updateFailedCw)
1341 const auto& staMissedTbPpduFrom = m_txTimer.GetStasExpectedToRespond();
1342 NS_LOG_FUNCTION(
this << psduMap << staMissedTbPpduFrom.size() << nSolicitedStations
1349 NS_ASSERT(!staMissedTbPpduFrom.empty());
1352 if (staMissedTbPpduFrom.size() == nSolicitedStations)
1356 psduMap->cbegin()->second->GetPayload(0)->PeekHeader(trigger);
1358 if (m_continueTxopAfterBsrpTf && m_edca->GetTxopLimit(m_linkId).IsZero() &&
1361 SendCfEndIfNeeded();
1364 TransmissionFailed(!updateFailedCw);
1366 else if (!m_multiStaBaEvent.IsPending())
1368 m_edca->ResetCw(m_linkId);
1369 TransmissionSucceeded();
1375 for (
const auto& address : staMissedTbPpduFrom)
1377 NS_LOG_DEBUG(address <<
" did not respond, hence it is no longer protected");
1378 m_protectedStas.erase(address);
1379 m_sentFrameTo.erase(address);
1381 if (m_protectedIfResponded)
1383 m_protectedStas.merge(m_sentFrameTo);
1385 m_sentFrameTo.clear();
1393 std::size_t nSolicitedStations)
1398 NS_ASSERT(m_txParams.m_acknowledgment &&
1399 (m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF ||
1400 m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_TF_MU_BAR));
1403 const auto& staMissedBlockAckFrom = m_txTimer.GetStasExpectedToRespond();
1404 NS_ASSERT(!staMissedBlockAckFrom.empty());
1406 if (staMissedBlockAckFrom.size() == nSolicitedStations)
1409 GetWifiRemoteStationManager()->ReportDataFailed(*psduMap->begin()->second->begin());
1415 m_triggerFrame =
nullptr;
1418 for (
const auto& sta : staMissedBlockAckFrom)
1420 auto psdu = GetPsduTo(sta, *psduMap);
1422 MissedBlockAck(psdu, m_txParams.m_txVector);
1427 if (staMissedBlockAckFrom.size() == nSolicitedStations)
1430 TransmissionFailed();
1434 m_edca->ResetCw(m_linkId);
1435 TransmissionSucceeded();
1445 GetWifiRemoteStationManager()->ReportDataFailed(*psdu->begin());
1447 MissedBlockAck(psdu, m_txParams.m_txVector);
1462 VhtFrameExchangeManager::NormalAckTimeout(mpdu, txVector);
1467 for (
auto& psdu : m_psduMap)
1471 if (mpdu->IsQueued())
1473 m_mac->GetTxopQueue(mpdu->GetQueueAc())->GetOriginal(mpdu)->GetHeader().SetRetry();
1474 mpdu->ResetInFlight(m_linkId);
1486 VhtFrameExchangeManager::BlockAckTimeout(psdu, txVector);
1491 for (
auto& psdu : m_psduMap)
1495 if (mpdu->IsQueued())
1497 mpdu->GetHeader().SetRetry();
1513 for (
const auto& userInfoField : trigger)
1516 userInfoField.GetAid12(),
1517 {userInfoField.GetRuAllocation(), userInfoField.GetUlMcs(), userInfoField.GetNss()});
1529 uint16_t staId = m_staMac->GetAssociationId();
1536 NS_ASSERT_MSG(heConfiguration,
"This STA has to be an HE station to send an HE TB PPDU");
1539 if (userInfoIt->IsUlTargetRssiMaxTxPower())
1541 NS_LOG_LOGIC(
"AP requested using the max transmit power (" << m_phy->GetTxPowerEnd()
1547 uint8_t powerLevel = GetWifiRemoteStationManager()->GetDefaultTxPowerLevel();
1565 auto optRssi = GetMostRecentRssi(triggerSender);
1571 auto reqTxPower =
static_cast<dBm_u>(userInfoIt->GetUlTargetRssi() + pathLossDb);
1574 uint8_t numPowerLevels = m_phy->GetNTxPower();
1575 if (numPowerLevels > 1)
1577 dBm_u step = (m_phy->GetTxPowerEnd() - m_phy->GetTxPowerStart()) / (numPowerLevels - 1);
1578 powerLevel =
static_cast<uint8_t
>(
1579 ceil((reqTxPower - m_phy->GetTxPowerStart()) /
1581 if (powerLevel > numPowerLevels)
1583 powerLevel = numPowerLevels;
1586 if (reqTxPower > m_phy->GetPower(powerLevel))
1588 NS_LOG_WARN(
"The requested power level (" << reqTxPower <<
"dBm) cannot be satisfied (max: "
1589 << m_phy->GetTxPowerEnd() <<
"dBm)");
1593 <<
"input {pathLoss=" << pathLossDb <<
"dB, reqTxPower=" << reqTxPower <<
"dBm}"
1594 <<
" output {powerLevel=" << +powerLevel <<
" -> " << m_phy->GetPower(powerLevel)
1596 <<
" PHY power capa {min=" << m_phy->GetTxPowerStart() <<
"dBm, max="
1597 << m_phy->GetTxPowerEnd() <<
"dBm, levels:" << +numPowerLevels <<
"}");
1603HeFrameExchangeManager::GetMostRecentRssi(
const Mac48Address& address)
const
1605 return GetWifiRemoteStationManager()->GetMostRecentRssi(address);
1615 m_phy->GetPower(GetWifiRemoteStationManager()->GetDefaultTxPowerLevel())));
1616 for (
auto& userInfo : trigger)
1618 const auto staList = m_apMac->GetStaList(m_linkId);
1619 auto itAidAddr = staList.find(userInfo.GetAid12());
1621 auto optRssi = GetMostRecentRssi(itAidAddr->second);
1623 auto rssi =
static_cast<int8_t>(*optRssi);
1624 rssi = (rssi >= -20)
1626 : ((rssi <= -110) ? -110 : rssi);
1627 userInfo.SetUlTargetRssi(rssi);
1636 auto txVectorCopy = txVector;
1638 if (psdu->GetNMpdus() == 1 && psdu->GetHeader(0).IsTrigger())
1641 psdu->GetPayload(0)->PeekHeader(trigger);
1655 if (m_staMac !=
nullptr && m_staMac->IsAssociated() &&
1666 psdu = Create<const WifiPsdu>(Create<Packet>(), rts);
1670 GetWifiRemoteStationManager()->GetCtsTxVector(m_bssid, GetCtsModeAfterMuRts());
1673 VhtFrameExchangeManager::PostProcessFrame(psdu, txVectorCopy);
1683 if (!UlMuCsMediumIdle(trigger))
1685 NS_LOG_DEBUG(
"UL MU CS indicated medium busy, cannot send CTS");
1689 NS_ASSERT(m_staMac !=
nullptr && m_staMac->IsAssociated());
1690 WifiTxVector ctsTxVector = GetCtsTxVectorAfterMuRts(trigger, m_staMac->GetAssociationId());
1693 DoSendCtsAfterRts(muRtsHdr, ctsTxVector, muRtsSnr);
1703 txParams.
m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
1706 NS_ASSERT(!acknowledgment->stationsReceivingMultiStaBa.empty());
1709 blockAck.
SetType(acknowledgment->baType);
1713 for (
const auto& staInfo : acknowledgment->stationsReceivingMultiStaBa)
1715 receiver = staInfo.first.first;
1716 uint8_t tid = staInfo.first.second;
1717 std::size_t index = staInfo.second;
1719 blockAck.
SetAid11(m_apMac->GetAssociationId(receiver, m_linkId), index);
1725 NS_LOG_DEBUG(
"Multi-STA Block Ack: Sending All-ack to=" << receiver);
1730 if (acknowledgment->baType.m_bitmapLen.at(index) == 0)
1733 NS_LOG_DEBUG(
"Multi-STA Block Ack: Sending Ack to=" << receiver);
1741 auto agreement = m_mac->GetBaAgreementEstablishedAsRecipient(receiver, tid);
1743 agreement->get().FillBlockAckBitmap(&blockAck, index);
1744 NS_LOG_DEBUG(
"Multi-STA Block Ack: Sending Block Ack with seq="
1746 <<
" tid=" << +tid);
1752 hdr.
SetAddr1(acknowledgment->stationsReceivingMultiStaBa.size() == 1
1754 : Mac48Address::GetBroadcast());
1760 packet->AddHeader(blockAck);
1762 GetWifiPsdu(Create<WifiMpdu>(packet, hdr), acknowledgment->multiStaBaTxVector);
1765 acknowledgment->multiStaBaTxVector,
1766 m_phy->GetPhyBand());
1778 if (m_edca->GetTxopLimit(m_linkId).IsZero())
1781 psdu->SetDuration(
Max(durationId - m_phy->GetSifs() - txDuration,
Seconds(0)));
1786 psdu->SetDuration(
Max(m_edca->GetRemainingTxop(m_linkId) - txDuration,
Seconds(0)));
1789 psdu->GetPayload(0)->AddPacketTag(m_muSnrTag);
1791 ForwardPsduDown(psdu, acknowledgment->multiStaBaTxVector);
1795 m_edca->ResetCw(m_linkId);
1797 Simulator::Schedule(txDuration, &HeFrameExchangeManager::TransmissionSucceeded,
this);
1806 NS_ASSERT(m_staMac && m_staMac->IsAssociated());
1808 NS_LOG_DEBUG(
"Received a Trigger Frame (basic variant) soliciting a transmission");
1810 if (!UlMuCsMediumIdle(trigger))
1821 std::vector<uint8_t> tids;
1822 uint16_t staId = m_staMac->GetAssociationId();
1825 for (uint8_t i = 0; i < 4; i++)
1828 tids.push_back(acIt->second.GetHighTid());
1829 tids.push_back(acIt->second.GetLowTid());
1841 Time ppduDuration = HePhy::ConvertLSigLengthToHeTbPpduDuration(trigger.
GetUlLength(),
1843 m_phy->GetPhyBand());
1845 for (
const auto& tid : tids)
1849 if (!m_mac->GetBaAgreementEstablishedAsOriginator(hdr.
GetAddr2(), tid))
1859 if (
auto mpdu = GetBar(edca->GetAccessCategory(), tid, hdr.
GetAddr2());
1860 mpdu && TryAddMpdu(mpdu, txParams, ppduDuration))
1863 psdu = Create<WifiPsdu>(mpdu,
true);
1869 GetWifiRemoteStationManager()->GetMldAddress(hdr.
GetAddr2()).value_or(hdr.
GetAddr2());
1870 if (
auto mpdu = edca->PeekNextMpdu(m_linkId, tid, receiver))
1872 mpdu = CreateAliasIfNeeded(mpdu);
1873 if (
auto item = edca->GetNextMpdu(m_linkId, mpdu, txParams, ppduDuration,
false))
1876 std::vector<Ptr<WifiMpdu>> mpduList =
1877 m_mpduAggregator->GetNextAmpdu(item, txParams, ppduDuration);
1878 psdu = (mpduList.size() > 1 ? Create<WifiPsdu>(std::move(mpduList))
1879 : Create<WifiPsdu>(item,
true));
1887 psdu->SetDuration(hdr.
GetDuration() - m_phy->GetSifs() - ppduDuration);
1888 SendPsduMapWithProtection(
WifiPsduMap{{staId, psdu}}, txParams);
1893 SendQosNullFramesInTbPpdu(trigger, hdr);
1903 NS_ASSERT(m_staMac && m_staMac->IsAssociated());
1907 if (!UlMuCsMediumIdle(trigger))
1913 GetWifiRemoteStationManager()->GetMldAddress(hdr.
GetAddr2()).value_or(hdr.
GetAddr2());
1916 header.
SetAddr2(m_mac->GetAddress());
1931 Time ppduDuration = HePhy::ConvertLSigLengthToHeTbPpduDuration(trigger.
GetUlLength(),
1933 m_phy->GetPhyBand());
1936 std::vector<Ptr<WifiMpdu>> mpduList;
1938 for (uint8_t tid = 0; tid < 8; ++tid)
1940 if (!m_mac->GetBaAgreementEstablishedAsOriginator(hdr.
GetAddr2(), tid))
1942 NS_LOG_DEBUG(
"Skipping tid=" << +tid <<
" because no agreement established");
1952 auto mpdu = Create<WifiMpdu>(Create<Packet>(), header);
1953 mpdu = CreateAliasIfNeeded(mpdu);
1955 UpdateTxDuration(header.
GetAddr1(), txParams);
1966 NS_LOG_DEBUG(
"Aggregating a QoS Null frame with tid=" << +tid);
1968 mpduList.push_back(mpdu);
1971 if (mpduList.empty())
1973 NS_LOG_DEBUG(
"Not enough time to send a QoS Null frame");
1977 Ptr<WifiPsdu> psdu = (mpduList.size() > 1 ? Create<WifiPsdu>(std::move(mpduList))
1978 : Create<WifiPsdu>(mpduList.front(),
true));
1979 uint16_t staId = m_staMac->GetAssociationId();
1980 SendPsduMapWithProtection(
WifiPsduMap{{staId, psdu}}, txParams);
1991 auto agreement = m_mac->GetBaAgreementEstablishedAsRecipient(m_bssid, tid);
1995 NS_LOG_DEBUG(
"There's not a valid agreement for this BlockAckReq");
1999 if (!UlMuCsMediumIdle(trigger))
2005 auto txVector = GetHeTbTxVector(trigger, m_bssid);
2006 SendBlockAck(*agreement, durationId, txVector, snr);
2020 const auto ra = psdu->GetAddr1();
2021 const auto ta = psdu->GetAddr2();
2022 const auto bssid = psdu->GetHeader(0).GetAddr3();
2025 if (ra == m_bssid || ta == m_bssid || bssid == m_bssid)
2033 if (psdu->GetHeader(0).IsCtl() && ta == empty && ra == m_txopHolder)
2047 if (bssid != empty && bssid != m_bssid)
2055 if (bssid == empty && ta != empty && ra != empty && ta != m_bssid && ra != m_bssid)
2068 const auto bssColor = m_mac->GetHeConfiguration()->m_bssColor;
2071 return bssColor != 0 && bssColor == txVector.
GetBssColor();
2079 if (!psdu->HasNav())
2084 if (psdu->GetAddr1() == m_self)
2094 if (!IsIntraBssPpdu(psdu, txVector))
2096 NS_LOG_DEBUG(
"PPDU not classified as intra-BSS, update the basic NAV");
2097 VhtFrameExchangeManager::UpdateNav(psdu, txVector);
2101 NS_LOG_DEBUG(
"PPDU classified as intra-BSS, update the intra-BSS NAV");
2102 Time duration = psdu->GetDuration();
2105 if (psdu->GetHeader(0).IsCfEnd())
2111 NS_LOG_DEBUG(
"Received CF-End, resetting the intra-BSS NAV");
2112 IntraBssNavResetTimeout();
2118 auto intraBssNavEnd = Simulator::Now() + duration;
2119 if (intraBssNavEnd > m_intraBssNavEnd)
2121 m_intraBssNavEnd = intraBssNavEnd;
2122 NS_LOG_DEBUG(
"Updated intra-BSS NAV=" << m_intraBssNavEnd);
2133 if (psdu->GetHeader(0).IsRts())
2136 GetWifiRemoteStationManager()->GetCtsTxVector(psdu->GetAddr2(), txVector.
GetMode());
2137 auto navResetDelay =
2138 2 * m_phy->GetSifs() +
2139 WifiPhy::CalculateTxDuration(
GetCtsSize(), ctsTxVector, m_phy->GetPhyBand()) +
2140 m_phy->CalculatePhyPreambleAndHeaderDuration(ctsTxVector) + 2 * m_phy->GetSlot();
2141 m_intraBssNavResetEvent =
2142 Simulator::Schedule(navResetDelay,
2143 &HeFrameExchangeManager::IntraBssNavResetTimeout,
2147 NS_LOG_DEBUG(
"Current intra-BSS NAV=" << m_intraBssNavEnd);
2149 m_channelAccessManager->NotifyNavStartNow(duration);
2153HeFrameExchangeManager::ClearTxopHolderIfNeeded()
2156 if (m_intraBssNavEnd <= Simulator::Now())
2158 m_txopHolder.reset();
2163HeFrameExchangeManager::NavResetTimeout()
2166 m_navEnd = Simulator::Now();
2169 Time intraBssNav = Simulator::GetDelayLeft(m_intraBssNavResetEvent);
2170 m_channelAccessManager->NotifyNavResetNow(intraBssNav);
2174HeFrameExchangeManager::IntraBssNavResetTimeout()
2177 m_intraBssNavEnd = Simulator::Now();
2178 ClearTxopHolderIfNeeded();
2180 Time basicNav = Simulator::GetDelayLeft(m_navResetEvent);
2181 m_channelAccessManager->NotifyNavResetNow(basicNav);
2184std::optional<Mac48Address>
2195 return VhtFrameExchangeManager::FindTxopHolder(hdr, txVector);
2197 return std::nullopt;
2201HeFrameExchangeManager::VirtualCsMediumIdle()
const
2206 return m_navEnd <= Simulator::Now() && m_intraBssNavEnd <= Simulator::Now();
2222 const Time now = Simulator::Now();
2229 NS_ASSERT_MSG(m_staMac,
"UL MU CS is only performed by non-AP STAs");
2232 "No User Info field for STA (" << m_self
2233 <<
") AID=" << m_staMac->GetAssociationId());
2235 std::set<uint8_t> indices;
2239 auto ctsTxVector = GetCtsTxVectorAfterMuRts(trigger, m_staMac->GetAssociationId());
2240 auto bw = ctsTxVector.GetChannelWidth();
2241 indices = m_phy->GetOperatingChannel().GetAll20MHzChannelIndicesInPrimary(bw);
2246 m_phy->GetOperatingChannel().Get20MHzIndicesCoveringRu(userInfoIt->GetRuAllocation(),
2249 return !m_channelAccessManager->GetPer20MHzBusy(indices);
2259 NS_ASSERT(mpdu->GetHeader().GetAddr1().IsGroup() || mpdu->GetHeader().GetAddr1() == m_self);
2263 if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
2264 m_txTimer.GetReason() == WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF)
2267 NS_ASSERT(m_txParams.m_acknowledgment &&
2268 m_txParams.m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
2269 auto acknowledgment =
static_cast<WifiUlMuMultiStaBa*
>(m_txParams.m_acknowledgment.get());
2272 if (!m_txTimer.GetStasExpectedToRespond().contains(sender))
2274 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2280 NS_LOG_DEBUG(
"Received a BlockAckReq in a TB PPDU from " << sender);
2283 mpdu->GetPacket()->PeekHeader(blockAckReq);
2286 GetBaManager(tid)->NotifyGotBlockAckRequest(
2287 m_mac->GetMldAddress(sender).value_or(sender),
2292 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, tid), index);
2293 acknowledgment->baType.m_bitmapLen.push_back(
2294 m_mac->GetBaTypeAsRecipient(sender, tid).m_bitmapLen.at(0));
2296 m_muSnrTag.Set(staId, rxSignalInfo.
snr);
2300 NS_LOG_DEBUG(
"Received an S-MPDU in a TB PPDU from " << sender <<
" (" << *mpdu <<
")");
2303 GetBaManager(tid)->NotifyGotMpdu(mpdu);
2306 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, tid), index);
2307 acknowledgment->baType.m_bitmapLen.push_back(0);
2309 m_muSnrTag.Set(staId, rxSignalInfo.
snr);
2318 VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
2323 if (!acknowledgment->stationsReceivingMultiStaBa.empty() && !m_multiStaBaEvent.IsPending())
2325 m_multiStaBaEvent = Simulator::Schedule(m_phy->GetSifs(),
2326 &HeFrameExchangeManager::SendMultiStaBlockAck,
2328 std::cref(m_txParams),
2329 mpdu->GetHeader().GetDuration());
2333 m_txTimer.GotResponseFrom(sender);
2335 if (m_txTimer.GetStasExpectedToRespond().empty())
2339 m_channelAccessManager->NotifyAckTimeoutResetNow();
2341 if (!m_multiStaBaEvent.IsPending())
2346 m_edca->ResetCw(m_linkId);
2347 TransmissionSucceeded();
2355 if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
2356 m_txTimer.GetReason() == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF &&
2359 const auto& sender = hdr.
GetAddr2();
2361 if (!m_txTimer.GetStasExpectedToRespond().contains(sender))
2363 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2368 NS_LOG_WARN(
"No QoS Null frame in the received MPDU");
2372 NS_LOG_DEBUG(
"Received a QoS Null frame in a TB PPDU from " << sender);
2373 ReceivedQosNullAfterBsrpTf(sender);
2381 if (hdr.
IsCts() && m_txTimer.IsRunning() &&
2382 m_txTimer.GetReason() == WifiTxTimer::WAIT_CTS && m_psduMap.size() == 1)
2387 Mac48Address sender = m_psduMap.begin()->second->GetAddr1();
2391 mpdu->GetPacket()->PeekPacketTag(tag);
2392 GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
2393 GetWifiRemoteStationManager()->ReportRtsOk(m_psduMap.begin()->second->GetHeader(0),
2399 m_channelAccessManager->NotifyCtsTimeoutResetNow();
2400 ProtectionCompleted();
2402 else if (hdr.
IsCts() && m_txTimer.IsRunning() &&
2403 m_txTimer.GetReason() == WifiTxTimer::WAIT_CTS_AFTER_MU_RTS)
2408 NS_LOG_DEBUG(
"Received a CTS frame in response to an MU-RTS");
2411 m_channelAccessManager->NotifyCtsTimeoutResetNow();
2412 ProtectionCompleted();
2414 else if (hdr.
IsAck() && m_txTimer.IsRunning() &&
2415 m_txTimer.GetReason() == WifiTxTimer::WAIT_NORMAL_ACK_AFTER_DL_MU_PPDU)
2419 NS_ASSERT(m_txParams.m_acknowledgment->method ==
2420 WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE);
2422 auto acknowledgment =
2424 NS_ASSERT(acknowledgment->stationsReplyingWithNormalAck.size() == 1);
2426 uint16_t staId = m_apMac->GetAssociationId(
2427 acknowledgment->stationsReplyingWithNormalAck.begin()->first,
2429 auto it = m_psduMap.find(staId);
2432 acknowledgment->stationsReplyingWithNormalAck.begin()->first);
2434 mpdu->GetPacket()->PeekPacketTag(tag);
2435 ReceivedNormalAck(*it->second->begin(),
2436 m_txParams.m_txVector,
2449 m_txTimer.GetReason() == WifiTxTimer::WAIT_BLOCK_ACKS_IN_TB_PPDU)
2452 NS_LOG_DEBUG(
"Received BlockAck in TB PPDU from=" << sender);
2455 mpdu->GetPacket()->PeekPacketTag(tag);
2459 mpdu->GetPacket()->PeekHeader(blockAck);
2461 std::pair<uint16_t, uint16_t> ret =
2462 GetBaManager(tid)->NotifyGotBlockAck(m_linkId,
2464 m_mac->GetMldAddress(sender).value_or(sender),
2466 GetWifiRemoteStationManager()->ReportAmpduTxStatus(sender,
2471 m_txParams.m_txVector);
2474 if (!m_txTimer.GetStasExpectedToRespond().contains(sender))
2476 NS_LOG_WARN(
"Received a BlockAck from an unexpected stations: " << sender);
2480 m_txTimer.GotResponseFrom(sender);
2482 if (m_txTimer.GetStasExpectedToRespond().empty())
2486 m_channelAccessManager->NotifyAckTimeoutResetNow();
2490 m_triggerFrame =
nullptr;
2493 m_edca->ResetCw(m_linkId);
2495 TransmissionSucceeded();
2498 else if (hdr.
IsBlockAck() && m_txTimer.IsRunning() &&
2499 m_txTimer.GetReason() == WifiTxTimer::WAIT_BLOCK_ACK_AFTER_TB_PPDU)
2502 mpdu->GetPacket()->PeekHeader(blockAck);
2505 "A Multi-STA BlockAck is expected after a TB PPDU");
2507 m_txTimer.GotResponseFrom(hdr.
GetAddr2());
2509 NS_ASSERT(m_staMac && m_staMac->IsAssociated());
2512 NS_LOG_DEBUG(
"The sender is not the AP we are associated with");
2516 uint16_t staId = m_staMac->GetAssociationId();
2519 if (indices.empty())
2521 NS_LOG_DEBUG(
"No Per AID TID Info subfield intended for me");
2526 mpdu->GetPacket()->PeekPacketTag(tag);
2529 for (
const auto& index : indices)
2536 NS_ABORT_IF(m_psduMap.empty() || m_psduMap.begin()->first != staId);
2537 GetBaManager(tid)->NotifyGotAck(m_linkId, *m_psduMap.at(staId)->begin());
2546 NS_ABORT_IF(m_psduMap.empty() || m_psduMap.begin()->first != staId);
2547 std::set<uint8_t> tids = m_psduMap.at(staId)->GetTids();
2548 NS_ABORT_MSG_IF(tids.size() > 1,
"Multi-TID A-MPDUs not supported yet");
2549 tid = *tids.begin();
2552 std::pair<uint16_t, uint16_t> ret = GetBaManager(tid)->NotifyGotBlockAck(
2558 GetWifiRemoteStationManager()->ReportAmpduTxStatus(hdr.
GetAddr2(),
2563 m_txParams.m_txVector);
2566 if (m_psduMap.at(staId)->GetHeader(0).IsQosData() &&
2568 || std::any_of(blockAck.
GetBitmap(index).begin(),
2570 [](uint8_t b) { return b != 0; })))
2572 NS_ASSERT(m_psduMap.at(staId)->GetHeader(0).HasData());
2573 NS_ASSERT(m_psduMap.at(staId)->GetHeader(0).GetQosTid() == tid);
2578 m_mac->GetQosTxop(tid)->StartMuEdcaTimerNow(m_linkId);
2584 m_channelAccessManager->NotifyAckTimeoutResetNow();
2586 for (
const auto& [staId, psdu] : m_psduMap)
2588 if (psdu->GetNMpdus() == 1 && psdu->GetHeader(0).IsBlockAckReq())
2595 else if (hdr.
IsBlockAck() && m_txTimer.IsRunning() &&
2596 m_txTimer.GetReason() == WifiTxTimer::WAIT_BLOCK_ACK)
2602 VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
2615 m_triggerFrameInAmpdu =
true;
2620 mpdu->GetPacket()->PeekHeader(trigger);
2631 uint16_t staId = m_staMac->GetAssociationId();
2636 NS_LOG_DEBUG(
"Received MU-RTS Trigger Frame from=" << sender);
2637 GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
2647 Simulator::Schedule(m_phy->GetSifs(),
2648 &HeFrameExchangeManager::SendCtsAfterMuRts,
2657 NS_LOG_DEBUG(
"Received MU-BAR Trigger Frame from=" << sender);
2658 GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
2666 GetBaManager(tid)->NotifyGotBlockAckRequest(
2667 m_mac->GetMldAddress(sender).value_or(sender),
2671 Simulator::Schedule(m_phy->GetSifs(),
2672 &HeFrameExchangeManager::ReceiveMuBarTrigger,
2681 Simulator::Schedule(m_phy->GetSifs(),
2682 &HeFrameExchangeManager::ReceiveBasicTrigger,
2687 else if (trigger.
IsBsrp())
2689 Simulator::Schedule(m_phy->GetSifs(),
2690 &HeFrameExchangeManager::SendQosNullFramesInTbPpdu,
2699 VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
2707 VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
2715 const std::vector<bool>& perMpduStatus)
2717 std::set<uint8_t> tids = psdu->GetTids();
2719 if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
2720 m_txTimer.GetReason() == WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF)
2723 NS_ASSERT(m_txParams.m_acknowledgment &&
2724 m_txParams.m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
2725 auto acknowledgment =
static_cast<WifiUlMuMultiStaBa*
>(m_txParams.m_acknowledgment.get());
2728 if (!m_txTimer.GetStasExpectedToRespond().contains(sender))
2730 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2734 NS_LOG_DEBUG(
"Received an A-MPDU in a TB PPDU from " << sender <<
" (" << *psdu <<
")");
2736 if (std::any_of(tids.begin(), tids.end(), [&psdu](uint8_t tid) {
2737 return psdu->GetAckPolicyForTid(tid) == WifiMacHeader::NORMAL_ACK;
2740 if (std::all_of(perMpduStatus.cbegin(), perMpduStatus.cend(), [](
bool v) { return v; }))
2743 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, 14),
2745 acknowledgment->baType.m_bitmapLen.push_back(0);
2751 for (
const auto& tid : tids)
2753 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, tid),
2755 acknowledgment->baType.m_bitmapLen.push_back(
2756 m_mac->GetBaTypeAsRecipient(sender, tid).m_bitmapLen.at(0));
2760 m_muSnrTag.Set(staId, rxSignalInfo.
snr);
2764 if (!acknowledgment->stationsReceivingMultiStaBa.empty() && !m_multiStaBaEvent.IsPending())
2766 m_multiStaBaEvent = Simulator::Schedule(m_phy->GetSifs(),
2767 &HeFrameExchangeManager::SendMultiStaBlockAck,
2769 std::cref(m_txParams),
2770 psdu->GetDuration());
2774 m_txTimer.GotResponseFrom(sender);
2776 if (m_txTimer.GetStasExpectedToRespond().empty())
2780 m_channelAccessManager->NotifyAckTimeoutResetNow();
2782 if (!m_multiStaBaEvent.IsPending())
2787 m_edca->ResetCw(m_linkId);
2788 TransmissionSucceeded();
2796 if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
2797 m_txTimer.GetReason() == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF)
2801 if (!m_txTimer.GetStasExpectedToRespond().contains(sender))
2803 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2806 if (std::none_of(psdu->begin(), psdu->end(), [](
Ptr<WifiMpdu> mpdu) {
2807 return mpdu->GetHeader().IsQosData() && !mpdu->GetHeader().HasData();
2810 NS_LOG_WARN(
"No QoS Null frame in the received PSDU");
2814 NS_LOG_DEBUG(
"Received QoS Null frames in a TB PPDU from " << sender);
2815 ReceivedQosNullAfterBsrpTf(sender);
2821 if (m_triggerFrameInAmpdu)
2824 auto psduIt = psdu->begin();
2825 while (psduIt != psdu->end())
2827 if ((*psduIt)->GetHeader().IsTrigger())
2829 ReceiveMpdu(*psduIt, rxSignalInfo, txVector,
false);
2834 m_triggerFrameInAmpdu =
false;
2839 VhtFrameExchangeManager::EndReceiveAmpdu(psdu, rxSignalInfo, txVector, perMpduStatus);
2848 m_txTimer.GetReason() == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF);
2851 m_txTimer.GotResponseFrom(sender);
2853 if (m_txTimer.GetStasExpectedToRespond().empty())
2856 m_channelAccessManager->NotifyAckTimeoutResetNow();
2860 m_edca->ResetCw(m_linkId);
2861 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
virtual void SetWifiMac(const Ptr< WifiMac > mac)
Set the MAC layer to use.
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< ChannelAccessManager > m_channelAccessManager
the channel access manager
MHz_u m_allowedWidth
the allowed width for the current transmission
virtual void RxStartIndication(WifiTxVector txVector, Time psduDuration)
virtual Time GetMuRtsDurationId(uint32_t muRtsSize, const WifiTxVector &muRtsTxVector, Time txDuration, Time response) const
Compute how to set the Duration/ID field of an MU-RTS Trigger Frame to send to protect a frame transm...
Ptr< ApWifiMac > m_apMac
MAC pointer (null if not an AP)
void DoDispose() override
Destructor implementation.
void Reset() override
Reset this frame exchange manager.
WifiMode GetCtsModeAfterMuRts() const
virtual void SendMuRts(const WifiTxParameters &txParams)
Send an MU-RTS to begin an MU-RTS/CTS frame exchange protecting an MU PPDU.
WifiTxParameters m_txParams
the TX parameters for the current PPDU
void RxStartIndication(WifiTxVector txVector, Time psduDuration) override
void CalculateAcknowledgmentTime(WifiAcknowledgment *acknowledgment) const override
Calculate the time required to acknowledge a frame according to the given acknowledgment method.
void DoCtsAfterMuRtsTimeout(Ptr< WifiMpdu > muRts, const WifiTxVector &txVector, bool updateFailedCw)
Called when no CTS frame is received after an MU-RTS.
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...
void SetWifiMac(const Ptr< WifiMac > mac) override
Set the MAC layer to use.
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,...
Ptr< StaWifiMac > m_staMac
MAC pointer (null if not a STA)
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)
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
bool IsTrigger(const WifiPsduMap &psduMap)
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
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.
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::unordered_map< uint16_t, Ptr< WifiPsdu > > WifiPsduMap
Map of PSDUs indexed by STA-ID.
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.