27#include "ns3/ap-wifi-mac.h"
28#include "ns3/erp-ofdm-phy.h"
30#include "ns3/recipient-block-ack-agreement.h"
31#include "ns3/snr-tag.h"
32#include "ns3/sta-wifi-mac.h"
33#include "ns3/wifi-mac-queue.h"
34#include "ns3/wifi-mac-trailer.h"
39#undef NS_LOG_APPEND_CONTEXT
40#define NS_LOG_APPEND_CONTEXT WIFI_FEM_NS_LOG_APPEND_CONTEXT
52 return psduMap.size() == 1 && psduMap.cbegin()->first ==
SU_STA_ID &&
53 psduMap.cbegin()->second->GetNMpdus() == 1 &&
54 psduMap.cbegin()->second->GetHeader(0).IsTrigger();
60 return psduMap.size() == 1 && psduMap.cbegin()->first ==
SU_STA_ID &&
61 psduMap.cbegin()->second->GetNMpdus() == 1 &&
62 psduMap.cbegin()->second->GetHeader(0).IsTrigger();
68 static TypeId tid =
TypeId(
"ns3::HeFrameExchangeManager")
70 .AddConstructor<HeFrameExchangeManager>()
71 .SetGroupName(
"Wifi");
76 : m_intraBssNavEnd(0),
77 m_triggerFrameInAmpdu(false)
102 m_apMac = DynamicCast<ApWifiMac>(mac);
103 m_staMac = DynamicCast<StaWifiMac>(mac);
135 "A Multi-User Scheduler can only be aggregated to an HE AP");
156 (!(mpdu = edca->PeekNextMpdu(
m_linkId)) ||
157 (mpdu->GetHeader().IsQosData() && !mpdu->GetHeader().GetAddr1().IsGroup() &&
159 mpdu->GetHeader().GetQosTid()))))
178 "The Multi-user Scheduler returned DL_MU_TX with empty psduMap, do not transmit");
189 auto packet = Create<Packet>();
229 <<
") incompatible with Basic Trigger Frame");
233 <<
") incompatible with BSRP Trigger Frame");
235 auto txVector = trigger.GetHeTbTxVector(trigger.begin()->GetAid12());
252 if (mpdu->IsQueued())
269 "Cannot use RTS/CTS with MU PPDUs");
294 for (
const auto& userInfo : protection->muRts)
296 const auto addressIt = aidAddrMap.find(userInfo.GetAid12());
297 NS_ASSERT_MSG(addressIt != aidAddrMap.end(),
"AID not found");
322 NS_LOG_FUNCTION(
this << muRtsSize << muRtsTxVector << txDuration << response);
357 protection->muRts.SetCsRequired(
true);
359 payload->AddHeader(protection->muRts);
361 auto mpdu = Create<WifiMpdu>(payload, hdr);
364 mpdu->GetHeader().SetDuration(
366 protection->muRtsTxVector,
379 protection->muRtsTxVector,
391 protection->muRtsTxVector);
415 if (mpdu->IsQueued())
423 const auto& hdr =
m_psduMap.cbegin()->second->GetHeader(0);
424 if (!hdr.GetAddr1().IsGroup())
429 if (!hdr.GetAddr1().IsGroup() &&
454 for (
const auto& [staId, psdu] :
m_psduMap)
465 auto it = std::find_if(
468 [&to](std::pair<uint16_t,
Ptr<WifiPsdu>> psdu) { return psdu.second->GetAddr1() == to; });
469 if (it != psduMap.end())
504 NS_LOG_DEBUG(address <<
" did not respond, hence it is no longer protected");
524 std::set<Mac48Address> staExpectResponseFrom;
533 auto acknowledgment =
539 if (acknowledgment->stationsSendBlockAckReqTo.contains(psdu.second->GetAddr1()))
542 std::set<uint8_t> tids = psdu.second->GetTids();
544 "Acknowledgment method incompatible with a Multi-TID A-MPDU");
545 uint8_t tid = *tids.begin();
554 if (!acknowledgment->stationsReplyingWithNormalAck.empty())
559 &acknowledgment->stationsReplyingWithNormalAck.begin()->second.ackTxVector;
560 auto from = acknowledgment->stationsReplyingWithNormalAck.begin()->first;
563 mpdu = *psdu->begin();
564 staExpectResponseFrom.insert(from);
566 else if (!acknowledgment->stationsReplyingWithBlockAck.empty())
571 &acknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
572 auto from = acknowledgment->stationsReplyingWithBlockAck.begin()->first;
574 staExpectResponseFrom.insert(from);
590 std::map<uint16_t, CtrlBAckRequestHeader> recipients;
592 NS_ASSERT(!acknowledgment->stationsReplyingWithBlockAck.empty());
593 auto staIt = acknowledgment->stationsReplyingWithBlockAck.begin();
595 while (staIt != acknowledgment->stationsReplyingWithBlockAck.end())
601 staIt->second.blockAckTxVector.GetHeMuUserInfo(staId));
602 recipients.emplace(staId, staIt->second.barHeader);
617 for (
auto& station : acknowledgment->stationsReplyingWithBlockAck)
619 staExpectResponseFrom.insert(station.first);
624 acknowledgment->muBarTxVector,
627 acknowledgment->acknowledgmentTime -= (
m_phy->
GetSifs() + txDuration);
631 &acknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
637 staExpectResponseFrom,
641 staExpectResponseFrom.size());
662 acknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
665 for (
auto& station : acknowledgment->stationsReplyingWithBlockAck)
667 staExpectResponseFrom.insert(station.first);
670 auto psduMapIt = std::find_if(
m_psduMap.begin(),
673 return psdu.second->GetAddr1() == station.first;
678 std::vector<Ptr<WifiMpdu>> mpduList(psduMapIt->second->begin(),
679 psduMapIt->second->end());
680 NS_ASSERT(mpduList.size() == psduMapIt->second->GetNMpdus());
683 station.second.blockAckTxVector.SetLength(acknowledgment->ulLength);
684 mpduList.push_back(
PrepareMuBar(station.second.blockAckTxVector,
685 {{psduMapIt->first, station.second.barHeader}}));
686 psduMapIt->second = Create<WifiPsdu>(std::move(mpduList));
689 station.second.blockAckTxVector.GetHeMuUserInfo(psduMapIt->first));
694 &acknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
704 mpdu = *m_psduMap.begin()->second->begin();
706 auto acknowledgment =
static_cast<WifiUlMuMultiStaBa*
>(m_txParams.m_acknowledgment.get());
709 for (
const auto& station : acknowledgment->stationsReceivingMultiStaBa)
711 staExpectResponseFrom.insert(station.first.first);
717 acknowledgment->baType.m_bitmapLen.clear();
720 responseTxVector = &acknowledgment->tbPpduTxVector;
721 m_trigVector = GetTrigVector(m_muScheduler->GetUlMuInfo(m_linkId).trigger);
727 !m_txParams.m_txVector.IsUlMu() &&
IsTrigger(m_psduMap))
729 CtrlTriggerHeader& trigger = m_muScheduler->GetUlMuInfo(m_linkId).trigger;
734 for (
const auto& userInfo : trigger)
736 auto staIt = m_apMac->GetStaList(m_linkId).find(userInfo.GetAid12());
737 NS_ASSERT(staIt != m_apMac->GetStaList(m_linkId).end());
738 staExpectResponseFrom.insert(staIt->second);
742 txVector = trigger.GetHeTbTxVector(trigger.begin()->GetAid12());
743 responseTxVector = &txVector;
744 m_trigVector = GetTrigVector(m_muScheduler->GetUlMuInfo(m_linkId).trigger);
749 else if (m_txParams.m_txVector.IsUlMu() &&
754 NS_ASSERT(m_staMac && m_staMac->IsAssociated());
755 auto recv = m_psduMap.begin()->second->GetAddr1();
756 txVector = GetWifiRemoteStationManager()->GetBlockAckTxVector(recv, m_txParams.m_txVector);
757 responseTxVector = &txVector;
758 staExpectResponseFrom.insert(recv);
763 else if (m_txParams.m_txVector.IsUlMu() &&
770 NS_ABORT_MSG(
"Unable to handle the selected acknowledgment method ("
771 << m_txParams.m_acknowledgment.get() <<
")");
776 for (
const auto& psdu : m_psduMap)
778 psduMap.emplace(psdu.first, psdu.second);
782 if (m_txParams.m_txVector.IsUlMu())
785 m_txParams.m_txVector,
786 m_phy->GetPhyBand());
791 m_phy->CalculateTxDuration(psduMap, m_txParams.m_txVector, m_phy->GetPhyBand());
794 Time durationId = GetPsduDurationId(txDuration, m_txParams);
795 for (
auto& psdu : m_psduMap)
797 psdu.second->SetDuration(durationId);
810 else if (!m_txParams.m_txVector.IsUlMu())
817 Time timeout = txDuration + m_phy->GetSifs() + m_phy->GetSlot() +
818 m_phy->CalculatePhyPreambleAndHeaderDuration(*responseTxVector);
819 m_channelAccessManager->NotifyAckTimeoutStartNow(
timeout);
826 m_txTimer.Set(timerType,
828 staExpectResponseFrom,
832 m_txParams.m_txVector);
836 m_txTimer.Set(timerType,
838 staExpectResponseFrom,
842 m_txParams.m_txVector);
845 m_txTimer.Set(timerType,
847 staExpectResponseFrom,
851 staExpectResponseFrom.size());
855 m_txTimer.Set(timerType,
857 staExpectResponseFrom,
861 staExpectResponseFrom.size());
864 m_txTimer.Set(timerType,
866 staExpectResponseFrom,
869 m_psduMap.begin()->second,
870 m_txParams.m_txVector);
879 ForwardPsduMapDown(psduMap, m_txParams.m_txVector);
886 auto hePhy = StaticCast<HePhy>(m_phy->GetPhyEntity(responseTxVector->GetModulationClass()));
887 hePhy->SetTrigVector(m_trigVector, m_txTimer.GetDelayLeft());
904 auto sigBMode = hePhy->GetSigBMode(txVector);
908 for (
const auto& psdu : psduMap)
910 NS_LOG_DEBUG(
"Transmitting: [STAID=" << psdu.first <<
", " << *psdu.second <<
"]");
913 for (
const auto& [staId, psdu] : psduMap)
915 FinalizeMacHeader(psdu);
916 NotifyTxToEdca(psdu);
920 if (psduMap.size() > 1 || psduMap.begin()->second->IsAggregate() ||
921 psduMap.begin()->second->IsSingle())
926 m_phy->Send(psduMap, txVector);
930HeFrameExchangeManager::PrepareMuBar(
const WifiTxVector& responseTxVector,
931 std::map<uint16_t, CtrlBAckRequestHeader> recipients)
const
938 SetTargetRssi(muBar);
944 for (
auto& userInfo : muBar)
946 auto recipientIt = recipients.find(userInfo.GetAid12());
947 NS_ASSERT(recipientIt != recipients.end());
950 userInfo.SetMuBarTriggerDepUserInfo(recipientIt->second);
954 bar->AddHeader(muBar);
962 rxAddress = Mac48Address::GetBroadcast();
967 rxAddress = m_apMac->GetStaList(m_linkId).at(recipients.begin()->first);
979 return Create<WifiMpdu>(bar, hdr);
988 if (protection->
method == WifiProtection::MU_RTS_CTS)
995 GetCtsTxVectorAfterMuRts(muRtsCtsProtection->muRts,
996 muRtsCtsProtection->muRts.begin()->GetAid12());
999 muRtsCtsProtection->muRts.GetSerializedSize() + WIFI_MAC_FCS_LENGTH;
1000 muRtsCtsProtection->protectionTime =
1001 m_phy->CalculateTxDuration(muRtsSize,
1002 muRtsCtsProtection->muRtsTxVector,
1003 m_phy->GetPhyBand()) +
1004 m_phy->CalculateTxDuration(
GetCtsSize(), ctsTxVector, m_phy->GetPhyBand()) +
1005 2 * m_phy->GetSifs();
1009 VhtFrameExchangeManager::CalculateProtectionTime(protection);
1022 if (acknowledgment->
method == WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE)
1029 NS_ABORT_IF(dlMuBarBaAcknowledgment->stationsReplyingWithNormalAck.size() +
1030 dlMuBarBaAcknowledgment->stationsReplyingWithBlockAck.size() >
1033 if (!dlMuBarBaAcknowledgment->stationsReplyingWithNormalAck.empty())
1036 dlMuBarBaAcknowledgment->stationsReplyingWithNormalAck.begin()->second;
1039 m_phy->CalculateTxDuration(
GetAckSize(), info.ackTxVector, m_phy->GetPhyBand());
1042 if (!dlMuBarBaAcknowledgment->stationsReplyingWithBlockAck.empty())
1045 dlMuBarBaAcknowledgment->stationsReplyingWithBlockAck.begin()->second;
1046 duration += m_phy->GetSifs() + m_phy->CalculateTxDuration(
GetBlockAckSize(info.baType),
1047 info.blockAckTxVector,
1048 m_phy->GetPhyBand());
1051 for (
const auto& stations : dlMuBarBaAcknowledgment->stationsSendBlockAckReqTo)
1053 const auto& info = stations.second;
1054 duration += m_phy->GetSifs() +
1056 info.blockAckReqTxVector,
1057 m_phy->GetPhyBand()) +
1060 info.blockAckTxVector,
1061 m_phy->GetPhyBand());
1064 dlMuBarBaAcknowledgment->acknowledgmentTime = duration;
1069 else if (acknowledgment->
method == WifiAcknowledgment::DL_MU_TF_MU_BAR)
1071 auto dlMuTfMuBarAcknowledgment =
static_cast<WifiDlMuTfMuBar*
>(acknowledgment);
1075 for (
const auto& stations : dlMuTfMuBarAcknowledgment->stationsReplyingWithBlockAck)
1078 const auto& info = stations.second;
1079 NS_ASSERT(info.blockAckTxVector.GetHeMuUserInfoMap().size() == 1);
1080 uint16_t staId = info.blockAckTxVector.GetHeMuUserInfoMap().begin()->first;
1082 info.blockAckTxVector,
1083 m_phy->GetPhyBand(),
1086 if (currBlockAckDuration > duration)
1088 duration = currBlockAckDuration;
1094 WifiTxVector& txVector = dlMuTfMuBarAcknowledgment->stationsReplyingWithBlockAck.begin()
1095 ->second.blockAckTxVector;
1096 std::tie(dlMuTfMuBarAcknowledgment->ulLength, duration) =
1097 HePhy::ConvertHeTbPpduDurationToLSigLength(duration, txVector, m_phy->GetPhyBand());
1100 if (dlMuTfMuBarAcknowledgment->muBarTxVector.GetModulationClass() >=
WIFI_MOD_CLASS_VHT)
1103 muBarSize = MpduAggregator::GetSizeIfAggregated(muBarSize, 0);
1105 dlMuTfMuBarAcknowledgment->acknowledgmentTime =
1107 m_phy->CalculateTxDuration(muBarSize,
1108 dlMuTfMuBarAcknowledgment->muBarTxVector,
1109 m_phy->GetPhyBand()) +
1110 m_phy->GetSifs() + duration;
1115 else if (acknowledgment->
method == WifiAcknowledgment::DL_MU_AGGREGATE_TF)
1121 for (
const auto& stations : dlMuAggrTfAcknowledgment->stationsReplyingWithBlockAck)
1124 const auto& info = stations.second;
1125 NS_ASSERT(info.blockAckTxVector.GetHeMuUserInfoMap().size() == 1);
1126 uint16_t staId = info.blockAckTxVector.GetHeMuUserInfoMap().begin()->first;
1128 info.blockAckTxVector,
1129 m_phy->GetPhyBand(),
1132 if (currBlockAckDuration > duration)
1134 duration = currBlockAckDuration;
1141 dlMuAggrTfAcknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
1142 std::tie(dlMuAggrTfAcknowledgment->ulLength, duration) =
1143 HePhy::ConvertHeTbPpduDurationToLSigLength(duration, txVector, m_phy->GetPhyBand());
1144 dlMuAggrTfAcknowledgment->acknowledgmentTime = m_phy->GetSifs() + duration;
1149 else if (acknowledgment->
method == WifiAcknowledgment::UL_MU_MULTI_STA_BA)
1154 ulMuMultiStaBa->multiStaBaTxVector,
1155 m_phy->GetPhyBand());
1156 ulMuMultiStaBa->acknowledgmentTime = m_phy->GetSifs() + duration;
1161 else if (acknowledgment->
method == WifiAcknowledgment::ACK_AFTER_TB_PPDU)
1170 VhtFrameExchangeManager::CalculateAcknowledgmentTime(acknowledgment);
1175HeFrameExchangeManager::GetCtsModeAfterMuRts()
const
1180 : OfdmPhy::GetOfdmRate6Mbps();
1185 uint16_t staId)
const
1190 NS_ASSERT_MSG(userInfoIt != trigger.
end(),
"User Info field for AID=" << staId <<
" not found");
1193 if (uint8_t ru = userInfoIt->GetMuRtsRuAllocation(); ru < 65)
1211 auto txVector = GetWifiRemoteStationManager()->GetCtsTxVector(m_bssid, GetCtsModeAfterMuRts());
1213 txVector.SetChannelWidth(bw);
1219HeFrameExchangeManager::GetTxDuration(
uint32_t ppduPayloadSize,
1225 return VhtFrameExchangeManager::GetTxDuration(ppduPayloadSize, receiver, txParams);
1232 txParams.
m_acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF)
1238 NS_ASSERT(info != acknowledgment->stationsReplyingWithBlockAck.end());
1241 MpduAggregator::GetSizeIfAggregated(info->second.muBarSize, ppduPayloadSize);
1244 uint16_t staId = (txParams.
m_txVector.
IsDlMu() ? m_apMac->GetAssociationId(receiver, m_linkId)
1245 : m_staMac->GetAssociationId());
1246 Time psduDuration = m_phy->CalculateTxDuration(ppduPayloadSize,
1248 m_phy->GetPhyBand(),
1255HeFrameExchangeManager::TbPpduTimeout(
WifiPsduMap* psduMap, std::size_t nSolicitedStations)
1257 const auto& staMissedTbPpduFrom = m_txTimer.GetStasExpectedToRespond();
1258 NS_LOG_FUNCTION(
this << psduMap << staMissedTbPpduFrom.size() << nSolicitedStations);
1264 NS_ASSERT(!staMissedTbPpduFrom.empty());
1267 if (staMissedTbPpduFrom.size() == nSolicitedStations)
1270 m_edca->UpdateFailedCw(m_linkId);
1272 TransmissionFailed();
1274 else if (!m_multiStaBaEvent.IsRunning())
1276 m_edca->ResetCw(m_linkId);
1277 TransmissionSucceeded();
1285 std::size_t nSolicitedStations)
1290 NS_ASSERT(m_txParams.m_acknowledgment &&
1291 (m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF ||
1292 m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_TF_MU_BAR));
1295 const auto& staMissedBlockAckFrom = m_txTimer.GetStasExpectedToRespond();
1296 NS_ASSERT(!staMissedBlockAckFrom.empty());
1300 if (staMissedBlockAckFrom.size() == nSolicitedStations)
1304 GetWifiRemoteStationManager()->ReportDataFailed(*psduMap->begin()->second->begin());
1316 m_triggerFrame =
nullptr;
1319 for (
const auto& sta : staMissedBlockAckFrom)
1328 MissedBlockAck(psdu, m_txParams.m_txVector, psduResetCw);
1329 resetCw = resetCw || psduResetCw;
1336 m_edca->ResetCw(m_linkId);
1340 m_edca->UpdateFailedCw(m_linkId);
1343 if (staMissedBlockAckFrom.size() == nSolicitedStations)
1346 TransmissionFailed();
1350 TransmissionSucceeded();
1363 GetWifiRemoteStationManager()->ReportDataFailed(*psdu->begin());
1365 MissedBlockAck(psdu, m_txParams.m_txVector, resetCw);
1380 VhtFrameExchangeManager::NormalAckTimeout(mpdu, txVector);
1385 for (
auto& psdu : m_psduMap)
1389 if (mpdu->IsQueued())
1391 m_mac->GetTxopQueue(mpdu->GetQueueAc())->GetOriginal(mpdu)->GetHeader().SetRetry();
1392 mpdu->ResetInFlight(m_linkId);
1404 VhtFrameExchangeManager::BlockAckTimeout(psdu, txVector);
1409 for (
auto& psdu : m_psduMap)
1413 if (mpdu->IsQueued())
1415 mpdu->GetHeader().SetRetry();
1431 for (
const auto& userInfoField : trigger)
1434 userInfoField.GetAid12(),
1435 {userInfoField.GetRuAllocation(), userInfoField.GetUlMcs(), userInfoField.GetNss()});
1447 uint16_t staId = m_staMac->GetAssociationId();
1454 NS_ASSERT_MSG(heConfiguration,
"This STA has to be an HE station to send an HE TB PPDU");
1457 if (userInfoIt->IsUlTargetRssiMaxTxPower())
1459 NS_LOG_LOGIC(
"AP requested using the max transmit power (" << m_phy->GetTxPowerEnd()
1465 uint8_t powerLevel = GetWifiRemoteStationManager()->GetDefaultTxPowerLevel();
1483 auto optRssi = GetMostRecentRssi(triggerSender);
1489 auto reqTxPowerDbm =
static_cast<double>(userInfoIt->GetUlTargetRssi() + pathLossDb);
1492 uint8_t numPowerLevels = m_phy->GetNTxPower();
1493 if (numPowerLevels > 1)
1495 double stepDbm = (m_phy->GetTxPowerEnd() - m_phy->GetTxPowerStart()) / (numPowerLevels - 1);
1496 powerLevel =
static_cast<uint8_t
>(
1497 ceil((reqTxPowerDbm - m_phy->GetTxPowerStart()) /
1499 if (powerLevel > numPowerLevels)
1501 powerLevel = numPowerLevels;
1504 if (reqTxPowerDbm > m_phy->GetPowerDbm(powerLevel))
1507 << reqTxPowerDbm <<
"dBm) cannot be satisfied (max: " << m_phy->GetTxPowerEnd()
1512 <<
"input {pathLoss=" << pathLossDb <<
"dB, reqTxPower=" << reqTxPowerDbm <<
"dBm}"
1513 <<
" output {powerLevel=" << +powerLevel <<
" -> "
1514 << m_phy->GetPowerDbm(powerLevel) <<
"dBm}"
1515 <<
" PHY power capa {min=" << m_phy->GetTxPowerStart() <<
"dBm, max="
1516 << m_phy->GetTxPowerEnd() <<
"dBm, levels:" << +numPowerLevels <<
"}");
1521std::optional<double>
1522HeFrameExchangeManager::GetMostRecentRssi(
const Mac48Address& address)
const
1524 return GetWifiRemoteStationManager()->GetMostRecentRssi(address);
1534 m_phy->GetPowerDbm(GetWifiRemoteStationManager()->GetDefaultTxPowerLevel())));
1535 for (
auto& userInfo : trigger)
1537 const auto staList = m_apMac->GetStaList(m_linkId);
1538 auto itAidAddr = staList.find(userInfo.GetAid12());
1540 auto optRssi = GetMostRecentRssi(itAidAddr->second);
1542 auto rssi =
static_cast<int8_t>(*optRssi);
1543 rssi = (rssi >= -20)
1545 : ((rssi <= -110) ? -110 : rssi);
1546 userInfo.SetUlTargetRssi(rssi);
1555 auto txVectorCopy = txVector;
1557 if (psdu->GetNMpdus() == 1 && psdu->GetHeader(0).IsTrigger())
1560 psdu->GetPayload(0)->PeekHeader(trigger);
1574 if (m_staMac !=
nullptr && m_staMac->IsAssociated() &&
1585 psdu = Create<const WifiPsdu>(Create<Packet>(), rts);
1589 GetWifiRemoteStationManager()->GetCtsTxVector(m_bssid, GetCtsModeAfterMuRts());
1592 VhtFrameExchangeManager::PostProcessFrame(psdu, txVectorCopy);
1602 if (!UlMuCsMediumIdle(trigger))
1604 NS_LOG_DEBUG(
"UL MU CS indicated medium busy, cannot send CTS");
1608 NS_ASSERT(m_staMac !=
nullptr && m_staMac->IsAssociated());
1609 WifiTxVector ctsTxVector = GetCtsTxVectorAfterMuRts(trigger, m_staMac->GetAssociationId());
1612 DoSendCtsAfterRts(muRtsHdr, ctsTxVector, muRtsSnr);
1622 txParams.
m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
1625 NS_ASSERT(!acknowledgment->stationsReceivingMultiStaBa.empty());
1628 blockAck.
SetType(acknowledgment->baType);
1632 for (
const auto& staInfo : acknowledgment->stationsReceivingMultiStaBa)
1634 receiver = staInfo.first.first;
1635 uint8_t tid = staInfo.first.second;
1636 std::size_t index = staInfo.second;
1638 blockAck.
SetAid11(m_apMac->GetAssociationId(receiver, m_linkId), index);
1644 NS_LOG_DEBUG(
"Multi-STA Block Ack: Sending All-ack to=" << receiver);
1649 if (acknowledgment->baType.m_bitmapLen.at(index) == 0)
1652 NS_LOG_DEBUG(
"Multi-STA Block Ack: Sending Ack to=" << receiver);
1660 auto agreement = m_mac->GetBaAgreementEstablishedAsRecipient(receiver, tid);
1662 agreement->get().FillBlockAckBitmap(&blockAck, index);
1663 NS_LOG_DEBUG(
"Multi-STA Block Ack: Sending Block Ack with seq="
1665 <<
" tid=" << +tid);
1671 hdr.
SetAddr1(acknowledgment->stationsReceivingMultiStaBa.size() == 1
1673 : Mac48Address::GetBroadcast());
1679 packet->AddHeader(blockAck);
1681 GetWifiPsdu(Create<WifiMpdu>(packet, hdr), acknowledgment->multiStaBaTxVector);
1684 acknowledgment->multiStaBaTxVector,
1685 m_phy->GetPhyBand());
1697 if (m_edca->GetTxopLimit(m_linkId).IsZero())
1700 psdu->SetDuration(
Max(durationId - m_phy->GetSifs() - txDuration,
Seconds(0)));
1705 psdu->SetDuration(
Max(m_edca->GetRemainingTxop(m_linkId) - txDuration,
Seconds(0)));
1708 psdu->GetPayload(0)->AddPacketTag(m_muSnrTag);
1710 ForwardPsduDown(psdu, acknowledgment->multiStaBaTxVector);
1714 m_edca->ResetCw(m_linkId);
1716 Simulator::Schedule(txDuration, &HeFrameExchangeManager::TransmissionSucceeded,
this);
1725 NS_ASSERT(m_staMac && m_staMac->IsAssociated());
1727 NS_LOG_DEBUG(
"Received a Trigger Frame (basic variant) soliciting a transmission");
1729 if (!UlMuCsMediumIdle(trigger))
1740 std::vector<uint8_t> tids;
1741 uint16_t staId = m_staMac->GetAssociationId();
1744 for (uint8_t i = 0; i < 4; i++)
1747 tids.push_back(acIt->second.GetHighTid());
1748 tids.push_back(acIt->second.GetLowTid());
1760 Time ppduDuration = HePhy::ConvertLSigLengthToHeTbPpduDuration(trigger.
GetUlLength(),
1762 m_phy->GetPhyBand());
1764 for (
const auto& tid : tids)
1768 if (!m_mac->GetBaAgreementEstablishedAsOriginator(hdr.
GetAddr2(), tid))
1778 if (
auto mpdu = GetBar(edca->GetAccessCategory(), tid, hdr.
GetAddr2());
1779 mpdu && TryAddMpdu(mpdu, txParams, ppduDuration))
1782 psdu = Create<WifiPsdu>(mpdu,
true);
1788 GetWifiRemoteStationManager()->GetMldAddress(hdr.
GetAddr2()).value_or(hdr.
GetAddr2());
1789 if (
auto mpdu = edca->PeekNextMpdu(m_linkId, tid, receiver))
1791 mpdu = CreateAliasIfNeeded(mpdu);
1792 if (
auto item = edca->GetNextMpdu(m_linkId, mpdu, txParams, ppduDuration,
false))
1795 std::vector<Ptr<WifiMpdu>> mpduList =
1796 m_mpduAggregator->GetNextAmpdu(item, txParams, ppduDuration);
1797 psdu = (mpduList.size() > 1 ? Create<WifiPsdu>(std::move(mpduList))
1798 : Create<WifiPsdu>(item,
true));
1806 psdu->SetDuration(hdr.
GetDuration() - m_phy->GetSifs() - ppduDuration);
1807 SendPsduMapWithProtection(
WifiPsduMap{{staId, psdu}}, txParams);
1812 SendQosNullFramesInTbPpdu(trigger, hdr);
1822 NS_ASSERT(m_staMac && m_staMac->IsAssociated());
1826 if (!UlMuCsMediumIdle(trigger))
1849 Time ppduDuration = HePhy::ConvertLSigLengthToHeTbPpduDuration(trigger.
GetUlLength(),
1851 m_phy->GetPhyBand());
1855 std::vector<Ptr<WifiMpdu>> mpduList;
1860 IsWithinSizeAndTimeLimits(
1861 txParams.
GetSizeIfAddMpdu(mpdu = Create<WifiMpdu>(Create<Packet>(), header)),
1866 if (!m_mac->GetBaAgreementEstablishedAsOriginator(hdr.
GetAddr2(), tid))
1868 NS_LOG_DEBUG(
"Skipping tid=" << +tid <<
" because no agreement established");
1873 NS_LOG_DEBUG(
"Aggregating a QoS Null frame with tid=" << +tid);
1881 UpdateTxDuration(mpdu->GetHeader().GetAddr1(), txParams);
1882 mpduList.push_back(mpdu);
1886 if (mpduList.empty())
1888 NS_LOG_DEBUG(
"Not enough time to send a QoS Null frame");
1892 Ptr<WifiPsdu> psdu = (mpduList.size() > 1 ? Create<WifiPsdu>(std::move(mpduList))
1893 : Create<WifiPsdu>(mpduList.front(),
true));
1894 uint16_t staId = m_staMac->GetAssociationId();
1895 SendPsduMapWithProtection(
WifiPsduMap{{staId, psdu}}, txParams);
1906 auto agreement = m_mac->GetBaAgreementEstablishedAsRecipient(m_bssid, tid);
1910 NS_LOG_DEBUG(
"There's not a valid agreement for this BlockAckReq");
1914 if (!UlMuCsMediumIdle(trigger))
1920 auto txVector = GetHeTbTxVector(trigger, m_bssid);
1921 SendBlockAck(*agreement, durationId, txVector, snr);
1935 const auto ra = psdu->GetAddr1();
1936 const auto ta = psdu->GetAddr2();
1937 const auto bssid = psdu->GetHeader(0).GetAddr3();
1940 if (ra == m_bssid || ta == m_bssid || bssid == m_bssid)
1948 if (psdu->GetHeader(0).IsCtl() && ta == empty && ra == m_txopHolder)
1962 if (bssid != empty && bssid != m_bssid)
1970 if (bssid == empty && ta != empty && ra != empty && ta != m_bssid && ra != m_bssid)
1983 const auto bssColor = m_mac->GetHeConfiguration()->GetBssColor();
1986 return bssColor != 0 && bssColor == txVector.
GetBssColor();
1994 if (!psdu->HasNav())
1999 if (psdu->GetAddr1() == m_self)
2009 if (!IsIntraBssPpdu(psdu, txVector))
2011 NS_LOG_DEBUG(
"PPDU not classified as intra-BSS, update the basic NAV");
2012 VhtFrameExchangeManager::UpdateNav(psdu, txVector);
2016 NS_LOG_DEBUG(
"PPDU classified as intra-BSS, update the intra-BSS NAV");
2017 Time duration = psdu->GetDuration();
2020 if (psdu->GetHeader(0).IsCfEnd())
2026 NS_LOG_DEBUG(
"Received CF-End, resetting the intra-BSS NAV");
2027 IntraBssNavResetTimeout();
2033 auto intraBssNavEnd = Simulator::Now() + duration;
2034 if (intraBssNavEnd > m_intraBssNavEnd)
2036 m_intraBssNavEnd = intraBssNavEnd;
2037 NS_LOG_DEBUG(
"Updated intra-BSS NAV=" << m_intraBssNavEnd);
2048 if (psdu->GetHeader(0).IsRts())
2051 GetWifiRemoteStationManager()->GetCtsTxVector(psdu->GetAddr2(), txVector.
GetMode());
2052 auto navResetDelay =
2053 2 * m_phy->GetSifs() +
2054 WifiPhy::CalculateTxDuration(
GetCtsSize(), ctsTxVector, m_phy->GetPhyBand()) +
2055 m_phy->CalculatePhyPreambleAndHeaderDuration(ctsTxVector) + 2 * m_phy->GetSlot();
2056 m_intraBssNavResetEvent =
2057 Simulator::Schedule(navResetDelay,
2058 &HeFrameExchangeManager::IntraBssNavResetTimeout,
2062 NS_LOG_DEBUG(
"Current intra-BSS NAV=" << m_intraBssNavEnd);
2064 m_channelAccessManager->NotifyNavStartNow(duration);
2068HeFrameExchangeManager::ClearTxopHolderIfNeeded()
2071 if (m_intraBssNavEnd <= Simulator::Now())
2073 m_txopHolder.reset();
2078HeFrameExchangeManager::NavResetTimeout()
2081 m_navEnd = Simulator::Now();
2084 Time intraBssNav = Simulator::GetDelayLeft(m_intraBssNavResetEvent);
2085 m_channelAccessManager->NotifyNavResetNow(intraBssNav);
2089HeFrameExchangeManager::IntraBssNavResetTimeout()
2092 m_intraBssNavEnd = Simulator::Now();
2093 ClearTxopHolderIfNeeded();
2095 Time basicNav = Simulator::GetDelayLeft(m_navResetEvent);
2096 m_channelAccessManager->NotifyNavResetNow(basicNav);
2104 if (psdu->GetHeader(0).IsTrigger() && psdu->GetAddr2() == m_bssid)
2106 m_txopHolder = m_bssid;
2108 else if (!txVector.
IsUlMu())
2110 VhtFrameExchangeManager::SetTxopHolder(psdu, txVector);
2115HeFrameExchangeManager::VirtualCsMediumIdle()
const
2120 return m_navEnd <= Simulator::Now() && m_intraBssNavEnd <= Simulator::Now();
2136 const Time now = Simulator::Now();
2143 NS_ASSERT_MSG(m_staMac,
"UL MU CS is only performed by non-AP STAs");
2146 "No User Info field for STA (" << m_self
2147 <<
") AID=" << m_staMac->GetAssociationId());
2149 std::set<uint8_t> indices;
2153 auto ctsTxVector = GetCtsTxVectorAfterMuRts(trigger, m_staMac->GetAssociationId());
2154 auto bw = ctsTxVector.GetChannelWidth();
2155 indices = m_phy->GetOperatingChannel().GetAll20MHzChannelIndicesInPrimary(bw);
2160 m_phy->GetOperatingChannel().Get20MHzIndicesCoveringRu(userInfoIt->GetRuAllocation(),
2163 return !m_channelAccessManager->GetPer20MHzBusy(indices);
2173 NS_ASSERT(mpdu->GetHeader().GetAddr1().IsGroup() || mpdu->GetHeader().GetAddr1() == m_self);
2177 if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
2178 m_txTimer.GetReason() == WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF)
2181 NS_ASSERT(m_txParams.m_acknowledgment &&
2182 m_txParams.m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
2183 auto acknowledgment =
static_cast<WifiUlMuMultiStaBa*
>(m_txParams.m_acknowledgment.get());
2186 if (!m_txTimer.GetStasExpectedToRespond().contains(sender))
2188 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2194 NS_LOG_DEBUG(
"Received a BlockAckReq in a TB PPDU from " << sender);
2197 mpdu->GetPacket()->PeekHeader(blockAckReq);
2200 GetBaManager(tid)->NotifyGotBlockAckRequest(
2201 m_mac->GetMldAddress(sender).value_or(sender),
2206 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, tid), index);
2207 acknowledgment->baType.m_bitmapLen.push_back(
2208 m_mac->GetBaTypeAsRecipient(sender, tid).m_bitmapLen.at(0));
2210 m_muSnrTag.Set(staId, rxSignalInfo.
snr);
2214 NS_LOG_DEBUG(
"Received an S-MPDU in a TB PPDU from " << sender <<
" (" << *mpdu <<
")");
2217 GetBaManager(tid)->NotifyGotMpdu(mpdu);
2220 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, tid), index);
2221 acknowledgment->baType.m_bitmapLen.push_back(0);
2223 m_muSnrTag.Set(staId, rxSignalInfo.
snr);
2232 VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
2237 if (!acknowledgment->stationsReceivingMultiStaBa.empty() && !m_multiStaBaEvent.IsRunning())
2239 m_multiStaBaEvent = Simulator::Schedule(m_phy->GetSifs(),
2240 &HeFrameExchangeManager::SendMultiStaBlockAck,
2242 std::cref(m_txParams),
2243 mpdu->GetHeader().GetDuration());
2247 m_txTimer.GotResponseFrom(sender);
2249 if (m_txTimer.GetStasExpectedToRespond().empty())
2253 m_channelAccessManager->NotifyAckTimeoutResetNow();
2255 if (!m_multiStaBaEvent.IsRunning())
2260 m_edca->ResetCw(m_linkId);
2261 TransmissionSucceeded();
2269 if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
2270 m_txTimer.GetReason() == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF &&
2273 const auto& sender = hdr.
GetAddr2();
2275 if (!m_txTimer.GetStasExpectedToRespond().contains(sender))
2277 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2282 NS_LOG_WARN(
"No QoS Null frame in the received MPDU");
2286 NS_LOG_DEBUG(
"Received a QoS Null frame in a TB PPDU from " << sender);
2289 m_txTimer.GotResponseFrom(sender);
2291 if (m_txTimer.GetStasExpectedToRespond().empty())
2295 m_channelAccessManager->NotifyAckTimeoutResetNow();
2299 m_edca->ResetCw(m_linkId);
2300 TransmissionSucceeded();
2309 if (hdr.
IsCts() && m_txTimer.IsRunning() &&
2310 m_txTimer.GetReason() == WifiTxTimer::WAIT_CTS && m_psduMap.size() == 1)
2315 Mac48Address sender = m_psduMap.begin()->second->GetAddr1();
2319 mpdu->GetPacket()->PeekPacketTag(tag);
2320 GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
2321 GetWifiRemoteStationManager()->ReportRtsOk(m_psduMap.begin()->second->GetHeader(0),
2327 m_channelAccessManager->NotifyCtsTimeoutResetNow();
2328 Simulator::Schedule(m_phy->GetSifs(),
2329 &HeFrameExchangeManager::ProtectionCompleted,
2332 else if (hdr.
IsCts() && m_txTimer.IsRunning() &&
2333 m_txTimer.GetReason() == WifiTxTimer::WAIT_CTS_AFTER_MU_RTS)
2338 NS_LOG_DEBUG(
"Received a CTS frame in response to an MU-RTS");
2341 m_channelAccessManager->NotifyCtsTimeoutResetNow();
2342 Simulator::Schedule(m_phy->GetSifs(),
2343 &HeFrameExchangeManager::ProtectionCompleted,
2346 else if (hdr.
IsAck() && m_txTimer.IsRunning() &&
2347 m_txTimer.GetReason() == WifiTxTimer::WAIT_NORMAL_ACK_AFTER_DL_MU_PPDU)
2351 NS_ASSERT(m_txParams.m_acknowledgment->method ==
2352 WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE);
2354 auto acknowledgment =
2356 NS_ASSERT(acknowledgment->stationsReplyingWithNormalAck.size() == 1);
2358 uint16_t staId = m_apMac->GetAssociationId(
2359 acknowledgment->stationsReplyingWithNormalAck.begin()->first,
2361 auto it = m_psduMap.find(staId);
2364 acknowledgment->stationsReplyingWithNormalAck.begin()->first);
2366 mpdu->GetPacket()->PeekPacketTag(tag);
2367 ReceivedNormalAck(*it->second->begin(),
2368 m_txParams.m_txVector,
2381 m_txTimer.GetReason() == WifiTxTimer::WAIT_BLOCK_ACKS_IN_TB_PPDU)
2384 NS_LOG_DEBUG(
"Received BlockAck in TB PPDU from=" << sender);
2387 mpdu->GetPacket()->PeekPacketTag(tag);
2391 mpdu->GetPacket()->PeekHeader(blockAck);
2393 std::pair<uint16_t, uint16_t> ret =
2394 GetBaManager(tid)->NotifyGotBlockAck(m_linkId,
2396 m_mac->GetMldAddress(sender).value_or(sender),
2398 GetWifiRemoteStationManager()->ReportAmpduTxStatus(sender,
2403 m_txParams.m_txVector);
2406 if (!m_txTimer.GetStasExpectedToRespond().contains(sender))
2408 NS_LOG_WARN(
"Received a BlockAck from an unexpected stations: " << sender);
2412 m_txTimer.GotResponseFrom(sender);
2414 if (m_txTimer.GetStasExpectedToRespond().empty())
2418 m_channelAccessManager->NotifyAckTimeoutResetNow();
2422 m_triggerFrame =
nullptr;
2425 m_edca->ResetCw(m_linkId);
2427 TransmissionSucceeded();
2430 else if (hdr.
IsBlockAck() && m_txTimer.IsRunning() &&
2431 m_txTimer.GetReason() == WifiTxTimer::WAIT_BLOCK_ACK_AFTER_TB_PPDU)
2434 mpdu->GetPacket()->PeekHeader(blockAck);
2437 "A Multi-STA BlockAck is expected after a TB PPDU");
2440 NS_ASSERT(m_staMac && m_staMac->IsAssociated());
2443 NS_LOG_DEBUG(
"The sender is not the AP we are associated with");
2447 uint16_t staId = m_staMac->GetAssociationId();
2450 if (indices.empty())
2452 NS_LOG_DEBUG(
"No Per AID TID Info subfield intended for me");
2457 mpdu->GetPacket()->PeekPacketTag(tag);
2460 for (
const auto& index : indices)
2467 NS_ABORT_IF(m_psduMap.empty() || m_psduMap.begin()->first != staId);
2468 GetBaManager(tid)->NotifyGotAck(m_linkId, *m_psduMap.at(staId)->begin());
2477 NS_ABORT_IF(m_psduMap.empty() || m_psduMap.begin()->first != staId);
2478 std::set<uint8_t> tids = m_psduMap.at(staId)->GetTids();
2479 NS_ABORT_MSG_IF(tids.size() > 1,
"Multi-TID A-MPDUs not supported yet");
2480 tid = *tids.begin();
2483 std::pair<uint16_t, uint16_t> ret = GetBaManager(tid)->NotifyGotBlockAck(
2489 GetWifiRemoteStationManager()->ReportAmpduTxStatus(hdr.
GetAddr2(),
2494 m_txParams.m_txVector);
2497 if (m_psduMap.at(staId)->GetHeader(0).IsQosData() &&
2499 || std::any_of(blockAck.
GetBitmap(index).begin(),
2501 [](uint8_t b) { return b != 0; })))
2503 NS_ASSERT(m_psduMap.at(staId)->GetHeader(0).HasData());
2504 NS_ASSERT(m_psduMap.at(staId)->GetHeader(0).GetQosTid() == tid);
2509 m_mac->GetQosTxop(tid)->StartMuEdcaTimerNow(m_linkId);
2515 m_channelAccessManager->NotifyAckTimeoutResetNow();
2517 for (
const auto& [staId, psdu] : m_psduMap)
2519 if (psdu->GetNMpdus() == 1 && psdu->GetHeader(0).IsBlockAckReq())
2526 else if (hdr.
IsBlockAck() && m_txTimer.IsRunning() &&
2527 m_txTimer.GetReason() == WifiTxTimer::WAIT_BLOCK_ACK)
2533 VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
2546 m_triggerFrameInAmpdu =
true;
2551 mpdu->GetPacket()->PeekHeader(trigger);
2562 uint16_t staId = m_staMac->GetAssociationId();
2567 NS_LOG_DEBUG(
"Received MU-RTS Trigger Frame from=" << sender);
2568 GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
2578 Simulator::Schedule(m_phy->GetSifs(),
2579 &HeFrameExchangeManager::SendCtsAfterMuRts,
2588 NS_LOG_DEBUG(
"Received MU-BAR Trigger Frame from=" << sender);
2589 GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
2597 GetBaManager(tid)->NotifyGotBlockAckRequest(
2598 m_mac->GetMldAddress(sender).value_or(sender),
2602 Simulator::Schedule(m_phy->GetSifs(),
2603 &HeFrameExchangeManager::ReceiveMuBarTrigger,
2612 Simulator::Schedule(m_phy->GetSifs(),
2613 &HeFrameExchangeManager::ReceiveBasicTrigger,
2618 else if (trigger.
IsBsrp())
2620 Simulator::Schedule(m_phy->GetSifs(),
2621 &HeFrameExchangeManager::SendQosNullFramesInTbPpdu,
2630 VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
2638 VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
2646 const std::vector<bool>& perMpduStatus)
2648 std::set<uint8_t> tids = psdu->GetTids();
2650 if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
2651 m_txTimer.GetReason() == WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF)
2654 NS_ASSERT(m_txParams.m_acknowledgment &&
2655 m_txParams.m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
2656 auto acknowledgment =
static_cast<WifiUlMuMultiStaBa*
>(m_txParams.m_acknowledgment.get());
2659 if (!m_txTimer.GetStasExpectedToRespond().contains(sender))
2661 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2665 NS_LOG_DEBUG(
"Received an A-MPDU in a TB PPDU from " << sender <<
" (" << *psdu <<
")");
2667 if (std::any_of(tids.begin(), tids.end(), [&psdu](uint8_t tid) {
2668 return psdu->GetAckPolicyForTid(tid) == WifiMacHeader::NORMAL_ACK;
2671 if (std::all_of(perMpduStatus.cbegin(), perMpduStatus.cend(), [](
bool v) { return v; }))
2674 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, 14),
2676 acknowledgment->baType.m_bitmapLen.push_back(0);
2682 for (
const auto& tid : tids)
2684 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, tid),
2686 acknowledgment->baType.m_bitmapLen.push_back(
2687 m_mac->GetBaTypeAsRecipient(sender, tid).m_bitmapLen.at(0));
2691 m_muSnrTag.Set(staId, rxSignalInfo.
snr);
2695 if (!acknowledgment->stationsReceivingMultiStaBa.empty() && !m_multiStaBaEvent.IsRunning())
2697 m_multiStaBaEvent = Simulator::Schedule(m_phy->GetSifs(),
2698 &HeFrameExchangeManager::SendMultiStaBlockAck,
2700 std::cref(m_txParams),
2701 psdu->GetDuration());
2705 m_txTimer.GotResponseFrom(sender);
2707 if (m_txTimer.GetStasExpectedToRespond().empty())
2711 m_channelAccessManager->NotifyAckTimeoutResetNow();
2713 if (!m_multiStaBaEvent.IsRunning())
2718 m_edca->ResetCw(m_linkId);
2719 TransmissionSucceeded();
2727 if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
2728 m_txTimer.GetReason() == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF)
2732 if (!m_txTimer.GetStasExpectedToRespond().contains(sender))
2734 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2737 if (std::none_of(psdu->begin(), psdu->end(), [](
Ptr<WifiMpdu> mpdu) {
2738 return mpdu->GetHeader().IsQosData() && !mpdu->GetHeader().HasData();
2741 NS_LOG_WARN(
"No QoS Null frame in the received PSDU");
2745 NS_LOG_DEBUG(
"Received QoS Null frames in a TB PPDU from " << sender);
2748 m_txTimer.GotResponseFrom(sender);
2750 if (m_txTimer.GetStasExpectedToRespond().empty())
2754 m_channelAccessManager->NotifyAckTimeoutResetNow();
2758 m_edca->ResetCw(m_linkId);
2759 TransmissionSucceeded();
2766 if (m_triggerFrameInAmpdu)
2769 auto psduIt = psdu->begin();
2770 while (psduIt != psdu->end())
2772 if ((*psduIt)->GetHeader().IsTrigger())
2774 ReceiveMpdu(*psduIt, rxSignalInfo, txVector,
false);
2779 m_triggerFrameInAmpdu =
false;
2784 VhtFrameExchangeManager::EndReceiveAmpdu(psdu, rxSignalInfo, txVector, perMpduStatus);
uint16_t GetAssociationId(Mac48Address addr, uint8_t linkId) const
const std::map< uint16_t, Mac48Address > & GetStaList(uint8_t linkId) const
Get a const reference to the map of associated stations on the given link.
void NotifyAckTimeoutStartNow(Time duration)
Notify that ack timer has started for the given duration.
void NotifyCtsTimeoutStartNow(Time duration)
Notify that CTS timer has started for the given duration.
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
bool IsRunning() 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
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.
uint16_t m_allowedWidth
the allowed width in MHz for the current transmission
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 upon successful protection mechanism.
virtual void CtsTimeout(Ptr< WifiMpdu > rts, const WifiTxVector &txVector)
Called when the CTS timeout expires.
virtual void TransmissionSucceeded()
Take necessary actions upon a transmission success.
Ptr< WifiPhy > m_phy
the PHY layer on this station
Ptr< ChannelAccessManager > m_channelAccessManager
the channel access manager
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
Ptr< WifiMpdu > PrepareMuBar(const WifiTxVector &responseTxVector, std::map< uint16_t, CtrlBAckRequestHeader > recipients) const
Build a MU-BAR Trigger Frame starting from the TXVECTOR used to respond to the MU-BAR (in case of mul...
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 BlockAckTimeout(Ptr< WifiPsdu > psdu, const WifiTxVector &txVector) override
Called when the BlockAck timeout expires.
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.
Ptr< WifiMpdu > m_triggerFrame
Trigger Frame being sent.
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.
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.
WifiTxVector m_trigVector
the TRIGVECTOR
void ProtectionCompleted() override
Transmit prepared frame upon successful protection mechanism.
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.
virtual void BlockAcksInTbPpduTimeout(WifiPsduMap *psduMap, std::size_t nSolicitedStations)
Take the necessary actions after that some BlockAck frames are missing in response to a DL MU PPDU.
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 NormalAckTimeout(Ptr< WifiMpdu > mpdu, const WifiTxVector &txVector) override
Called when the Ack timeout expires.
virtual void BlockAckAfterTbPpduTimeout(Ptr< WifiPsdu > psdu, const WifiTxVector &txVector)
Take the necessary actions after that a Block Ack is missing after a TB PPDU solicited through a Trig...
virtual void TbPpduTimeout(WifiPsduMap *psduMap, std::size_t nSolicitedStations)
Take the necessary actions after that some TB PPDUs are missing in response to Trigger Frame.
void SendPsduMap()
Send the current PSDU map as a DL MU PPDU.
WifiPsduMap m_psduMap
the A-MPDU being transmitted
void RecordSentMuRtsTo(const WifiTxParameters &txParams)
Record the stations being solicited by an MU-RTS TF.
static TypeId GetTypeId()
Get the type ID.
Time m_intraBssNavEnd
intra-BSS NAV expiration time
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.
virtual Time GetPsduDurationId(Time txDuration, const WifiTxParameters &txParams) const
Compute how to set the Duration/ID field of PSDUs that do not include fragments.
void 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 NotifyPacketDiscarded(Ptr< const WifiMpdu > mpdu) override
Pass the given MPDU, discarded because of the max retry limit was reached, to the MPDU dropped callba...
virtual void ForwardPsduDown(Ptr< const WifiPsdu > psdu, WifiTxVector &txVector)
Forward a PSDU down to the PHY layer.
void DequeuePsdu(Ptr< const WifiPsdu > psdu)
Dequeue the MPDUs of the given PSDU from the queue in which they are stored.
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.
void TransmissionFailed() override
Take necessary actions upon a transmission failure.
Ptr< QosTxop > m_edca
the EDCAF that gained channel access
Ptr< BlockAckManager > GetBaManager()
Get the Block Ack Manager associated with this QosTxop.
virtual Time GetRemainingTxop(uint8_t linkId) const
Return the remaining duration in the current TXOP on the given link.
std::pair< CtrlBAckRequestHeader, WifiMacHeader > PrepareBlockAckRequest(Mac48Address recipient, uint8_t tid) const
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.
static Time Min()
Minimum representable Time Not to be confused with Min(Time,Time).
bool IsZero() const
Exactly equivalent to t == 0.
Time GetTxopLimit() const
Return the TXOP limit.
void UpdateFailedCw(uint8_t linkId)
Update the value of the CW variable for the given link to take into account a transmission failure.
void ResetCw(uint8_t linkId)
Update the value of the CW variable for the given link to take into account a transmission success or...
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.
Ptr< HeConfiguration > GetHeConfiguration() const
OriginatorAgreementOptConstRef GetBaAgreementEstablishedAsOriginator(Mac48Address recipient, uint8_t tid) const
Ptr< QosTxop > GetQosTxop(AcIndex ac) const
Accessor for a specified EDCA object.
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.
Ptr< PhyEntity > GetPhyEntity(WifiModulationClass modulation) const
Get the supported PHY entity corresponding to the modulation class.
static Time CalculatePhyPreambleAndHeaderDuration(const WifiTxVector &txVector)
This class stores the TX parameters (TX vector, protection mechanism, acknowledgment mechanism,...
uint32_t GetSizeIfAddMpdu(Ptr< const WifiMpdu > mpdu) const
Get the size in bytes of the frame in case the given MPDU is added.
std::unique_ptr< WifiProtection > m_protection
protection method
std::unique_ptr< WifiAcknowledgment > m_acknowledgment
acknowledgment method
Time m_txDuration
TX duration of the frame.
WifiTxVector m_txVector
TXVECTOR of the frame being prepared.
void AddMpdu(Ptr< const 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_BLOCK_ACK_AFTER_TB_PPDU
@ WAIT_NORMAL_ACK_AFTER_DL_MU_PPDU
@ WAIT_QOS_NULL_AFTER_BSRP_TF
@ WAIT_TB_PPDU_AFTER_BASIC_TF
@ WAIT_BLOCK_ACKS_IN_TB_PPDU
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.
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.
void SetChannelWidth(uint16_t channelWidth)
Sets the selected channelWidth (in MHz)
uint8_t GetBssColor() const
Get the BSS color.
void SetGuardInterval(uint16_t 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.
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.
void SetSigBMode(const WifiMode &mode)
Set the MCS used for SIG-B.
void SetBssColor(uint8_t color)
Set the BSS color.
uint16_t GetChannelWidth() const
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_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
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)
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.
Time acknowledgmentTime
time required by the acknowledgment method
const Method method
acknowledgment method
WifiDlMuAggregateTf specifies that a DL MU PPDU made of PSDUs including each a MU-BAR Trigger Frame i...
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.