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 std::clog << "[link=" << +m_linkId << "][mac=" << m_self << "] "
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)
113 m_apMac = DynamicCast<ApWifiMac>(mac);
114 m_staMac = DynamicCast<StaWifiMac>(mac);
146 "A Multi-User Scheduler can only be aggregated to an HE AP");
167 (!(mpdu = edca->PeekNextMpdu(
m_linkId)) ||
168 (mpdu->GetHeader().IsQosData() && !mpdu->GetHeader().GetAddr1().IsGroup() &&
170 mpdu->GetHeader().GetQosTid()))))
189 "The Multi-user Scheduler returned DL_MU_TX with empty psduMap, do not transmit");
200 auto packet = Create<Packet>();
240 <<
") incompatible with Basic Trigger Frame");
244 <<
") incompatible with BSRP Trigger Frame");
246 auto txVector = trigger.GetHeTbTxVector(trigger.begin()->GetAid12());
263 if (mpdu->IsQueued())
280 "Cannot use RTS/CTS with MU PPDUs");
305 for (
const auto& userInfo : protection->muRts)
307 const auto addressIt = aidAddrMap.find(userInfo.GetAid12());
308 NS_ASSERT_MSG(addressIt != aidAddrMap.end(),
"AID not found");
333 NS_LOG_FUNCTION(
this << muRtsSize << muRtsTxVector << txDuration << response);
368 protection->muRts.SetCsRequired(
true);
370 payload->AddHeader(protection->muRts);
372 auto mpdu = Create<WifiMpdu>(payload, hdr);
375 mpdu->GetHeader().SetDuration(
377 protection->muRtsTxVector,
390 protection->muRtsTxVector,
402 protection->muRtsTxVector);
426 if (mpdu->IsQueued())
434 const auto& hdr =
m_psduMap.cbegin()->second->GetHeader(0);
435 if (!hdr.GetAddr1().IsGroup())
440 if (!hdr.GetAddr1().IsGroup() &&
465 for (
const auto& [staId, psdu] :
m_psduMap)
476 auto it = std::find_if(
479 [&to](std::pair<uint16_t,
Ptr<WifiPsdu>> psdu) { return psdu.second->GetAddr1() == to; });
480 if (it != psduMap.end())
515 NS_LOG_DEBUG(address <<
" did not respond, hence it is no longer protected");
535 std::set<Mac48Address> staExpectResponseFrom;
544 auto acknowledgment =
550 if (acknowledgment->stationsSendBlockAckReqTo.find(psdu.second->GetAddr1()) !=
551 acknowledgment->stationsSendBlockAckReqTo.end())
554 std::set<uint8_t> tids = psdu.second->GetTids();
556 "Acknowledgment method incompatible with a Multi-TID A-MPDU");
557 uint8_t tid = *tids.begin();
566 if (!acknowledgment->stationsReplyingWithNormalAck.empty())
571 &acknowledgment->stationsReplyingWithNormalAck.begin()->second.ackTxVector;
572 auto from = acknowledgment->stationsReplyingWithNormalAck.begin()->first;
575 mpdu = *psdu->begin();
576 staExpectResponseFrom.insert(from);
578 else if (!acknowledgment->stationsReplyingWithBlockAck.empty())
583 &acknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
584 auto from = acknowledgment->stationsReplyingWithBlockAck.begin()->first;
586 staExpectResponseFrom.insert(from);
602 std::map<uint16_t, CtrlBAckRequestHeader> recipients;
604 NS_ASSERT(!acknowledgment->stationsReplyingWithBlockAck.empty());
605 auto staIt = acknowledgment->stationsReplyingWithBlockAck.begin();
607 while (staIt != acknowledgment->stationsReplyingWithBlockAck.end())
613 staIt->second.blockAckTxVector.GetHeMuUserInfo(staId));
614 recipients.emplace(staId, staIt->second.barHeader);
629 for (
auto& station : acknowledgment->stationsReplyingWithBlockAck)
631 staExpectResponseFrom.insert(station.first);
636 acknowledgment->muBarTxVector,
639 acknowledgment->acknowledgmentTime -= (
m_phy->
GetSifs() + txDuration);
643 &acknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
649 staExpectResponseFrom,
653 staExpectResponseFrom.size());
674 acknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
677 for (
auto& station : acknowledgment->stationsReplyingWithBlockAck)
679 staExpectResponseFrom.insert(station.first);
682 auto psduMapIt = std::find_if(
m_psduMap.begin(),
685 return psdu.second->GetAddr1() == station.first;
690 std::vector<Ptr<WifiMpdu>> mpduList(psduMapIt->second->begin(),
691 psduMapIt->second->end());
692 NS_ASSERT(mpduList.size() == psduMapIt->second->GetNMpdus());
695 station.second.blockAckTxVector.SetLength(acknowledgment->ulLength);
696 mpduList.push_back(
PrepareMuBar(station.second.blockAckTxVector,
697 {{psduMapIt->first, station.second.barHeader}}));
698 psduMapIt->second = Create<WifiPsdu>(std::move(mpduList));
701 station.second.blockAckTxVector.GetHeMuUserInfo(psduMapIt->first));
706 &acknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
716 mpdu = *m_psduMap.begin()->second->begin();
718 auto acknowledgment =
static_cast<WifiUlMuMultiStaBa*
>(m_txParams.m_acknowledgment.get());
721 for (
const auto& station : acknowledgment->stationsReceivingMultiStaBa)
723 staExpectResponseFrom.insert(station.first.first);
729 acknowledgment->baType.m_bitmapLen.clear();
732 responseTxVector = &acknowledgment->tbPpduTxVector;
733 m_trigVector = GetTrigVector(m_muScheduler->GetUlMuInfo(m_linkId).trigger);
739 !m_txParams.m_txVector.IsUlMu() &&
IsTrigger(m_psduMap))
741 CtrlTriggerHeader& trigger = m_muScheduler->GetUlMuInfo(m_linkId).trigger;
746 for (
const auto& userInfo : trigger)
748 auto staIt = m_apMac->GetStaList(m_linkId).find(userInfo.GetAid12());
749 NS_ASSERT(staIt != m_apMac->GetStaList(m_linkId).end());
750 staExpectResponseFrom.insert(staIt->second);
754 txVector = trigger.GetHeTbTxVector(trigger.begin()->GetAid12());
755 responseTxVector = &txVector;
756 m_trigVector = GetTrigVector(m_muScheduler->GetUlMuInfo(m_linkId).trigger);
761 else if (m_txParams.m_txVector.IsUlMu() &&
766 NS_ASSERT(m_staMac && m_staMac->IsAssociated());
767 auto recv = m_psduMap.begin()->second->GetAddr1();
768 txVector = GetWifiRemoteStationManager()->GetBlockAckTxVector(recv, m_txParams.m_txVector);
769 responseTxVector = &txVector;
770 staExpectResponseFrom.insert(recv);
775 else if (m_txParams.m_txVector.IsUlMu() &&
782 NS_ABORT_MSG(
"Unable to handle the selected acknowledgment method ("
783 << m_txParams.m_acknowledgment.get() <<
")");
788 for (
const auto& psdu : m_psduMap)
790 psduMap.emplace(psdu.first, psdu.second);
794 if (m_txParams.m_txVector.IsUlMu())
797 m_txParams.m_txVector,
798 m_phy->GetPhyBand());
803 m_phy->CalculateTxDuration(psduMap, m_txParams.m_txVector, m_phy->GetPhyBand());
806 Time durationId = GetPsduDurationId(txDuration, m_txParams);
807 for (
auto& psdu : m_psduMap)
809 psdu.second->SetDuration(durationId);
822 else if (!m_txParams.m_txVector.IsUlMu())
829 Time timeout = txDuration + m_phy->GetSifs() + m_phy->GetSlot() +
830 m_phy->CalculatePhyPreambleAndHeaderDuration(*responseTxVector);
831 m_channelAccessManager->NotifyAckTimeoutStartNow(
timeout);
838 m_txTimer.Set(timerType,
840 staExpectResponseFrom,
844 m_txParams.m_txVector);
848 m_txTimer.Set(timerType,
850 staExpectResponseFrom,
854 m_txParams.m_txVector);
857 m_txTimer.Set(timerType,
859 staExpectResponseFrom,
863 staExpectResponseFrom.size());
867 m_txTimer.Set(timerType,
869 staExpectResponseFrom,
873 staExpectResponseFrom.size());
876 m_txTimer.Set(timerType,
878 staExpectResponseFrom,
881 m_psduMap.begin()->second,
882 m_txParams.m_txVector);
891 ForwardPsduMapDown(psduMap, m_txParams.m_txVector);
898 auto hePhy = StaticCast<HePhy>(m_phy->GetPhyEntity(responseTxVector->GetModulationClass()));
899 hePhy->SetTrigVector(m_trigVector, m_txTimer.GetDelayLeft());
916 auto sigBMode = hePhy->GetSigBMode(txVector);
920 for (
const auto& psdu : psduMap)
922 NS_LOG_DEBUG(
"Transmitting: [STAID=" << psdu.first <<
", " << *psdu.second <<
"]");
925 for (
const auto& [staId, psdu] : psduMap)
927 FinalizeMacHeader(psdu);
928 NotifyTxToEdca(psdu);
932 if (psduMap.size() > 1 || psduMap.begin()->second->IsAggregate() ||
933 psduMap.begin()->second->IsSingle())
938 m_phy->Send(psduMap, txVector);
942HeFrameExchangeManager::PrepareMuBar(
const WifiTxVector& responseTxVector,
943 std::map<uint16_t, CtrlBAckRequestHeader> recipients)
const
950 SetTargetRssi(muBar);
956 for (
auto& userInfo : muBar)
958 auto recipientIt = recipients.find(userInfo.GetAid12());
959 NS_ASSERT(recipientIt != recipients.end());
962 userInfo.SetMuBarTriggerDepUserInfo(recipientIt->second);
966 bar->AddHeader(muBar);
974 rxAddress = Mac48Address::GetBroadcast();
979 rxAddress = m_apMac->GetStaList(m_linkId).at(recipients.begin()->first);
991 return Create<WifiMpdu>(bar, hdr);
1000 if (protection->
method == WifiProtection::MU_RTS_CTS)
1007 GetCtsTxVectorAfterMuRts(muRtsCtsProtection->muRts,
1008 muRtsCtsProtection->muRts.begin()->GetAid12());
1011 muRtsCtsProtection->muRts.GetSerializedSize() + WIFI_MAC_FCS_LENGTH;
1012 muRtsCtsProtection->protectionTime =
1013 m_phy->CalculateTxDuration(muRtsSize,
1014 muRtsCtsProtection->muRtsTxVector,
1015 m_phy->GetPhyBand()) +
1016 m_phy->CalculateTxDuration(
GetCtsSize(), ctsTxVector, m_phy->GetPhyBand()) +
1017 2 * m_phy->GetSifs();
1021 VhtFrameExchangeManager::CalculateProtectionTime(protection);
1034 if (acknowledgment->
method == WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE)
1041 NS_ABORT_IF(dlMuBarBaAcknowledgment->stationsReplyingWithNormalAck.size() +
1042 dlMuBarBaAcknowledgment->stationsReplyingWithBlockAck.size() >
1045 if (!dlMuBarBaAcknowledgment->stationsReplyingWithNormalAck.empty())
1048 dlMuBarBaAcknowledgment->stationsReplyingWithNormalAck.begin()->second;
1051 m_phy->CalculateTxDuration(
GetAckSize(), info.ackTxVector, m_phy->GetPhyBand());
1054 if (!dlMuBarBaAcknowledgment->stationsReplyingWithBlockAck.empty())
1057 dlMuBarBaAcknowledgment->stationsReplyingWithBlockAck.begin()->second;
1058 duration += m_phy->GetSifs() + m_phy->CalculateTxDuration(
GetBlockAckSize(info.baType),
1059 info.blockAckTxVector,
1060 m_phy->GetPhyBand());
1063 for (
const auto& stations : dlMuBarBaAcknowledgment->stationsSendBlockAckReqTo)
1065 const auto& info = stations.second;
1066 duration += m_phy->GetSifs() +
1068 info.blockAckReqTxVector,
1069 m_phy->GetPhyBand()) +
1072 info.blockAckTxVector,
1073 m_phy->GetPhyBand());
1076 dlMuBarBaAcknowledgment->acknowledgmentTime = duration;
1081 else if (acknowledgment->
method == WifiAcknowledgment::DL_MU_TF_MU_BAR)
1083 auto dlMuTfMuBarAcknowledgment =
static_cast<WifiDlMuTfMuBar*
>(acknowledgment);
1087 for (
const auto& stations : dlMuTfMuBarAcknowledgment->stationsReplyingWithBlockAck)
1090 const auto& info = stations.second;
1091 NS_ASSERT(info.blockAckTxVector.GetHeMuUserInfoMap().size() == 1);
1092 uint16_t staId = info.blockAckTxVector.GetHeMuUserInfoMap().begin()->first;
1094 info.blockAckTxVector,
1095 m_phy->GetPhyBand(),
1098 if (currBlockAckDuration > duration)
1100 duration = currBlockAckDuration;
1106 WifiTxVector& txVector = dlMuTfMuBarAcknowledgment->stationsReplyingWithBlockAck.begin()
1107 ->second.blockAckTxVector;
1108 std::tie(dlMuTfMuBarAcknowledgment->ulLength, duration) =
1109 HePhy::ConvertHeTbPpduDurationToLSigLength(duration, txVector, m_phy->GetPhyBand());
1112 if (dlMuTfMuBarAcknowledgment->muBarTxVector.GetModulationClass() >=
WIFI_MOD_CLASS_VHT)
1115 muBarSize = MpduAggregator::GetSizeIfAggregated(muBarSize, 0);
1117 dlMuTfMuBarAcknowledgment->acknowledgmentTime =
1119 m_phy->CalculateTxDuration(muBarSize,
1120 dlMuTfMuBarAcknowledgment->muBarTxVector,
1121 m_phy->GetPhyBand()) +
1122 m_phy->GetSifs() + duration;
1127 else if (acknowledgment->
method == WifiAcknowledgment::DL_MU_AGGREGATE_TF)
1133 for (
const auto& stations : dlMuAggrTfAcknowledgment->stationsReplyingWithBlockAck)
1136 const auto& info = stations.second;
1137 NS_ASSERT(info.blockAckTxVector.GetHeMuUserInfoMap().size() == 1);
1138 uint16_t staId = info.blockAckTxVector.GetHeMuUserInfoMap().begin()->first;
1140 info.blockAckTxVector,
1141 m_phy->GetPhyBand(),
1144 if (currBlockAckDuration > duration)
1146 duration = currBlockAckDuration;
1153 dlMuAggrTfAcknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
1154 std::tie(dlMuAggrTfAcknowledgment->ulLength, duration) =
1155 HePhy::ConvertHeTbPpduDurationToLSigLength(duration, txVector, m_phy->GetPhyBand());
1156 dlMuAggrTfAcknowledgment->acknowledgmentTime = m_phy->GetSifs() + duration;
1161 else if (acknowledgment->
method == WifiAcknowledgment::UL_MU_MULTI_STA_BA)
1166 ulMuMultiStaBa->multiStaBaTxVector,
1167 m_phy->GetPhyBand());
1168 ulMuMultiStaBa->acknowledgmentTime = m_phy->GetSifs() + duration;
1173 else if (acknowledgment->
method == WifiAcknowledgment::ACK_AFTER_TB_PPDU)
1182 VhtFrameExchangeManager::CalculateAcknowledgmentTime(acknowledgment);
1187HeFrameExchangeManager::GetCtsModeAfterMuRts()
const
1192 : OfdmPhy::GetOfdmRate6Mbps();
1197 uint16_t staId)
const
1202 NS_ASSERT_MSG(userInfoIt != trigger.
end(),
"User Info field for AID=" << staId <<
" not found");
1205 if (uint8_t ru = userInfoIt->GetMuRtsRuAllocation(); ru < 65)
1223 auto txVector = GetWifiRemoteStationManager()->GetCtsTxVector(m_bssid, GetCtsModeAfterMuRts());
1225 txVector.SetChannelWidth(bw);
1231HeFrameExchangeManager::GetTxDuration(
uint32_t ppduPayloadSize,
1237 return VhtFrameExchangeManager::GetTxDuration(ppduPayloadSize, receiver, txParams);
1244 txParams.
m_acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF)
1250 NS_ASSERT(info != acknowledgment->stationsReplyingWithBlockAck.end());
1253 MpduAggregator::GetSizeIfAggregated(info->second.muBarSize, ppduPayloadSize);
1256 uint16_t staId = (txParams.
m_txVector.
IsDlMu() ? m_apMac->GetAssociationId(receiver, m_linkId)
1257 : m_staMac->GetAssociationId());
1258 Time psduDuration = m_phy->CalculateTxDuration(ppduPayloadSize,
1260 m_phy->GetPhyBand(),
1267HeFrameExchangeManager::TbPpduTimeout(
WifiPsduMap* psduMap, std::size_t nSolicitedStations)
1269 const auto& staMissedTbPpduFrom = m_txTimer.GetStasExpectedToRespond();
1270 NS_LOG_FUNCTION(
this << psduMap << staMissedTbPpduFrom.size() << nSolicitedStations);
1276 NS_ASSERT(!staMissedTbPpduFrom.empty());
1279 if (staMissedTbPpduFrom.size() == nSolicitedStations)
1282 m_edca->UpdateFailedCw(m_linkId);
1284 TransmissionFailed();
1286 else if (!m_multiStaBaEvent.IsRunning())
1288 m_edca->ResetCw(m_linkId);
1289 TransmissionSucceeded();
1297 std::size_t nSolicitedStations)
1302 NS_ASSERT(m_txParams.m_acknowledgment &&
1303 (m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF ||
1304 m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_TF_MU_BAR));
1307 const auto& staMissedBlockAckFrom = m_txTimer.GetStasExpectedToRespond();
1308 NS_ASSERT(!staMissedBlockAckFrom.empty());
1312 if (staMissedBlockAckFrom.size() == nSolicitedStations)
1316 GetWifiRemoteStationManager()->ReportDataFailed(*psduMap->begin()->second->begin());
1328 m_triggerFrame =
nullptr;
1331 for (
const auto& sta : staMissedBlockAckFrom)
1340 MissedBlockAck(psdu, m_txParams.m_txVector, psduResetCw);
1341 resetCw = resetCw || psduResetCw;
1348 m_edca->ResetCw(m_linkId);
1352 m_edca->UpdateFailedCw(m_linkId);
1355 if (staMissedBlockAckFrom.size() == nSolicitedStations)
1358 TransmissionFailed();
1362 TransmissionSucceeded();
1375 GetWifiRemoteStationManager()->ReportDataFailed(*psdu->begin());
1377 MissedBlockAck(psdu, m_txParams.m_txVector, resetCw);
1392 VhtFrameExchangeManager::NormalAckTimeout(mpdu, txVector);
1397 for (
auto& psdu : m_psduMap)
1401 if (mpdu->IsQueued())
1403 m_mac->GetTxopQueue(mpdu->GetQueueAc())->GetOriginal(mpdu)->GetHeader().SetRetry();
1404 mpdu->ResetInFlight(m_linkId);
1416 VhtFrameExchangeManager::BlockAckTimeout(psdu, txVector);
1421 for (
auto& psdu : m_psduMap)
1425 if (mpdu->IsQueued())
1427 mpdu->GetHeader().SetRetry();
1443 for (
const auto& userInfoField : trigger)
1446 userInfoField.GetAid12(),
1447 {userInfoField.GetRuAllocation(), userInfoField.GetUlMcs(), userInfoField.GetNss()});
1459 uint16_t staId = m_staMac->GetAssociationId();
1466 NS_ASSERT_MSG(heConfiguration,
"This STA has to be an HE station to send an HE TB PPDU");
1469 if (userInfoIt->IsUlTargetRssiMaxTxPower())
1471 NS_LOG_LOGIC(
"AP requested using the max transmit power (" << m_phy->GetTxPowerEnd()
1477 uint8_t powerLevel = GetWifiRemoteStationManager()->GetDefaultTxPowerLevel();
1495 auto optRssi = GetMostRecentRssi(triggerSender);
1501 auto reqTxPowerDbm =
static_cast<double>(userInfoIt->GetUlTargetRssi() + pathLossDb);
1504 uint8_t numPowerLevels = m_phy->GetNTxPower();
1505 if (numPowerLevels > 1)
1507 double stepDbm = (m_phy->GetTxPowerEnd() - m_phy->GetTxPowerStart()) / (numPowerLevels - 1);
1508 powerLevel =
static_cast<uint8_t
>(
1509 ceil((reqTxPowerDbm - m_phy->GetTxPowerStart()) /
1511 if (powerLevel > numPowerLevels)
1513 powerLevel = numPowerLevels;
1516 if (reqTxPowerDbm > m_phy->GetPowerDbm(powerLevel))
1519 << reqTxPowerDbm <<
"dBm) cannot be satisfied (max: " << m_phy->GetTxPowerEnd()
1524 <<
"input {pathLoss=" << pathLossDb <<
"dB, reqTxPower=" << reqTxPowerDbm <<
"dBm}"
1525 <<
" output {powerLevel=" << +powerLevel <<
" -> "
1526 << m_phy->GetPowerDbm(powerLevel) <<
"dBm}"
1527 <<
" PHY power capa {min=" << m_phy->GetTxPowerStart() <<
"dBm, max="
1528 << m_phy->GetTxPowerEnd() <<
"dBm, levels:" << +numPowerLevels <<
"}");
1533std::optional<double>
1534HeFrameExchangeManager::GetMostRecentRssi(
const Mac48Address& address)
const
1536 return GetWifiRemoteStationManager()->GetMostRecentRssi(address);
1546 m_phy->GetPowerDbm(GetWifiRemoteStationManager()->GetDefaultTxPowerLevel())));
1547 for (
auto& userInfo : trigger)
1549 const auto staList = m_apMac->GetStaList(m_linkId);
1550 auto itAidAddr = staList.find(userInfo.GetAid12());
1552 auto optRssi = GetMostRecentRssi(itAidAddr->second);
1554 auto rssi =
static_cast<int8_t>(*optRssi);
1555 rssi = (rssi >= -20)
1557 : ((rssi <= -110) ? -110 : rssi);
1558 userInfo.SetUlTargetRssi(rssi);
1567 auto txVectorCopy = txVector;
1569 if (psdu->GetNMpdus() == 1 && psdu->GetHeader(0).IsTrigger())
1572 psdu->GetPayload(0)->PeekHeader(trigger);
1586 if (m_staMac !=
nullptr && m_staMac->IsAssociated() &&
1597 psdu = Create<const WifiPsdu>(Create<Packet>(), rts);
1601 GetWifiRemoteStationManager()->GetCtsTxVector(m_bssid, GetCtsModeAfterMuRts());
1604 VhtFrameExchangeManager::PostProcessFrame(psdu, txVectorCopy);
1614 if (!UlMuCsMediumIdle(trigger))
1616 NS_LOG_DEBUG(
"UL MU CS indicated medium busy, cannot send CTS");
1620 NS_ASSERT(m_staMac !=
nullptr && m_staMac->IsAssociated());
1621 WifiTxVector ctsTxVector = GetCtsTxVectorAfterMuRts(trigger, m_staMac->GetAssociationId());
1624 DoSendCtsAfterRts(muRtsHdr, ctsTxVector, muRtsSnr);
1634 txParams.
m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
1637 NS_ASSERT(!acknowledgment->stationsReceivingMultiStaBa.empty());
1640 blockAck.
SetType(acknowledgment->baType);
1644 for (
const auto& staInfo : acknowledgment->stationsReceivingMultiStaBa)
1646 receiver = staInfo.first.first;
1647 uint8_t tid = staInfo.first.second;
1648 std::size_t index = staInfo.second;
1650 blockAck.
SetAid11(m_apMac->GetAssociationId(receiver, m_linkId), index);
1656 NS_LOG_DEBUG(
"Multi-STA Block Ack: Sending All-ack to=" << receiver);
1661 if (acknowledgment->baType.m_bitmapLen.at(index) == 0)
1664 NS_LOG_DEBUG(
"Multi-STA Block Ack: Sending Ack to=" << receiver);
1672 auto agreement = m_mac->GetBaAgreementEstablishedAsRecipient(receiver, tid);
1674 agreement->get().FillBlockAckBitmap(&blockAck, index);
1675 NS_LOG_DEBUG(
"Multi-STA Block Ack: Sending Block Ack with seq="
1677 <<
" tid=" << +tid);
1683 hdr.
SetAddr1(acknowledgment->stationsReceivingMultiStaBa.size() == 1
1685 : Mac48Address::GetBroadcast());
1691 packet->AddHeader(blockAck);
1693 GetWifiPsdu(Create<WifiMpdu>(packet, hdr), acknowledgment->multiStaBaTxVector);
1696 acknowledgment->multiStaBaTxVector,
1697 m_phy->GetPhyBand());
1709 if (m_edca->GetTxopLimit(m_linkId).IsZero())
1712 psdu->SetDuration(
Max(durationId - m_phy->GetSifs() - txDuration,
Seconds(0)));
1717 psdu->SetDuration(
Max(m_edca->GetRemainingTxop(m_linkId) - txDuration,
Seconds(0)));
1720 psdu->GetPayload(0)->AddPacketTag(m_muSnrTag);
1722 ForwardPsduDown(psdu, acknowledgment->multiStaBaTxVector);
1726 m_edca->ResetCw(m_linkId);
1728 Simulator::Schedule(txDuration, &HeFrameExchangeManager::TransmissionSucceeded,
this);
1737 NS_ASSERT(m_staMac && m_staMac->IsAssociated());
1739 NS_LOG_DEBUG(
"Received a Trigger Frame (basic variant) soliciting a transmission");
1741 if (!UlMuCsMediumIdle(trigger))
1752 std::vector<uint8_t> tids;
1753 uint16_t staId = m_staMac->GetAssociationId();
1756 for (uint8_t i = 0; i < 4; i++)
1759 tids.push_back(acIt->second.GetHighTid());
1760 tids.push_back(acIt->second.GetLowTid());
1772 Time ppduDuration = HePhy::ConvertLSigLengthToHeTbPpduDuration(trigger.
GetUlLength(),
1774 m_phy->GetPhyBand());
1776 for (
const auto& tid : tids)
1780 if (!m_mac->GetBaAgreementEstablishedAsOriginator(hdr.
GetAddr2(), tid))
1790 if (
auto mpdu = GetBar(edca->GetAccessCategory(), tid, hdr.
GetAddr2());
1791 mpdu && TryAddMpdu(mpdu, txParams, ppduDuration))
1794 psdu = Create<WifiPsdu>(mpdu,
true);
1800 GetWifiRemoteStationManager()->GetMldAddress(hdr.
GetAddr2()).value_or(hdr.
GetAddr2());
1801 if (
auto mpdu = edca->PeekNextMpdu(m_linkId, tid, receiver))
1803 mpdu = CreateAliasIfNeeded(mpdu);
1804 if (
auto item = edca->GetNextMpdu(m_linkId, mpdu, txParams, ppduDuration,
false))
1807 std::vector<Ptr<WifiMpdu>> mpduList =
1808 m_mpduAggregator->GetNextAmpdu(item, txParams, ppduDuration);
1809 psdu = (mpduList.size() > 1 ? Create<WifiPsdu>(std::move(mpduList))
1810 : Create<WifiPsdu>(item,
true));
1818 psdu->SetDuration(hdr.
GetDuration() - m_phy->GetSifs() - ppduDuration);
1819 SendPsduMapWithProtection(
WifiPsduMap{{staId, psdu}}, txParams);
1824 SendQosNullFramesInTbPpdu(trigger, hdr);
1834 NS_ASSERT(m_staMac && m_staMac->IsAssociated());
1838 if (!UlMuCsMediumIdle(trigger))
1861 Time ppduDuration = HePhy::ConvertLSigLengthToHeTbPpduDuration(trigger.
GetUlLength(),
1863 m_phy->GetPhyBand());
1867 std::vector<Ptr<WifiMpdu>> mpduList;
1872 IsWithinSizeAndTimeLimits(
1873 txParams.
GetSizeIfAddMpdu(mpdu = Create<WifiMpdu>(Create<Packet>(), header)),
1878 if (!m_mac->GetBaAgreementEstablishedAsOriginator(hdr.
GetAddr2(), tid))
1880 NS_LOG_DEBUG(
"Skipping tid=" << +tid <<
" because no agreement established");
1885 NS_LOG_DEBUG(
"Aggregating a QoS Null frame with tid=" << +tid);
1893 UpdateTxDuration(mpdu->GetHeader().GetAddr1(), txParams);
1894 mpduList.push_back(mpdu);
1898 if (mpduList.empty())
1900 NS_LOG_DEBUG(
"Not enough time to send a QoS Null frame");
1904 Ptr<WifiPsdu> psdu = (mpduList.size() > 1 ? Create<WifiPsdu>(std::move(mpduList))
1905 : Create<WifiPsdu>(mpduList.front(),
true));
1906 uint16_t staId = m_staMac->GetAssociationId();
1907 SendPsduMapWithProtection(
WifiPsduMap{{staId, psdu}}, txParams);
1918 auto agreement = m_mac->GetBaAgreementEstablishedAsRecipient(m_bssid, tid);
1922 NS_LOG_DEBUG(
"There's not a valid agreement for this BlockAckReq");
1926 if (!UlMuCsMediumIdle(trigger))
1932 auto txVector = GetHeTbTxVector(trigger, m_bssid);
1933 SendBlockAck(*agreement, durationId, txVector, snr);
1947 const auto ra = psdu->GetAddr1();
1948 const auto ta = psdu->GetAddr2();
1949 const auto bssid = psdu->GetHeader(0).GetAddr3();
1952 if (ra == m_bssid || ta == m_bssid || bssid == m_bssid)
1960 if (psdu->GetHeader(0).IsCtl() && ta == empty && ra == m_txopHolder)
1974 if (bssid != empty && bssid != m_bssid)
1982 if (bssid == empty && ta != empty && ra != empty && ta != m_bssid && ra != m_bssid)
1995 const auto bssColor = m_mac->GetHeConfiguration()->GetBssColor();
1998 return bssColor != 0 && bssColor == txVector.
GetBssColor();
2006 if (!psdu->HasNav())
2011 if (psdu->GetAddr1() == m_self)
2021 if (!IsIntraBssPpdu(psdu, txVector))
2023 NS_LOG_DEBUG(
"PPDU not classified as intra-BSS, update the basic NAV");
2024 VhtFrameExchangeManager::UpdateNav(psdu, txVector);
2028 NS_LOG_DEBUG(
"PPDU classified as intra-BSS, update the intra-BSS NAV");
2029 Time duration = psdu->GetDuration();
2032 if (psdu->GetHeader(0).IsCfEnd())
2038 NS_LOG_DEBUG(
"Received CF-End, resetting the intra-BSS NAV");
2039 IntraBssNavResetTimeout();
2045 auto intraBssNavEnd = Simulator::Now() + duration;
2046 if (intraBssNavEnd > m_intraBssNavEnd)
2048 m_intraBssNavEnd = intraBssNavEnd;
2049 NS_LOG_DEBUG(
"Updated intra-BSS NAV=" << m_intraBssNavEnd);
2060 if (psdu->GetHeader(0).IsRts())
2063 GetWifiRemoteStationManager()->GetCtsTxVector(psdu->GetAddr2(), txVector.
GetMode());
2064 auto navResetDelay =
2065 2 * m_phy->GetSifs() +
2066 WifiPhy::CalculateTxDuration(
GetCtsSize(), ctsTxVector, m_phy->GetPhyBand()) +
2067 m_phy->CalculatePhyPreambleAndHeaderDuration(ctsTxVector) + 2 * m_phy->GetSlot();
2068 m_intraBssNavResetEvent =
2069 Simulator::Schedule(navResetDelay,
2070 &HeFrameExchangeManager::IntraBssNavResetTimeout,
2074 NS_LOG_DEBUG(
"Current intra-BSS NAV=" << m_intraBssNavEnd);
2076 m_channelAccessManager->NotifyNavStartNow(duration);
2080HeFrameExchangeManager::ClearTxopHolderIfNeeded()
2083 if (m_intraBssNavEnd <= Simulator::Now())
2085 m_txopHolder.reset();
2090HeFrameExchangeManager::NavResetTimeout()
2093 m_navEnd = Simulator::Now();
2096 Time intraBssNav = Simulator::GetDelayLeft(m_intraBssNavResetEvent);
2097 m_channelAccessManager->NotifyNavResetNow(intraBssNav);
2101HeFrameExchangeManager::IntraBssNavResetTimeout()
2104 m_intraBssNavEnd = Simulator::Now();
2105 ClearTxopHolderIfNeeded();
2107 Time basicNav = Simulator::GetDelayLeft(m_navResetEvent);
2108 m_channelAccessManager->NotifyNavResetNow(basicNav);
2116 if (psdu->GetHeader(0).IsTrigger() && psdu->GetAddr2() == m_bssid)
2118 m_txopHolder = m_bssid;
2120 else if (!txVector.
IsUlMu())
2122 VhtFrameExchangeManager::SetTxopHolder(psdu, txVector);
2127HeFrameExchangeManager::VirtualCsMediumIdle()
const
2132 return m_navEnd <= Simulator::Now() && m_intraBssNavEnd <= Simulator::Now();
2148 const Time now = Simulator::Now();
2155 NS_ASSERT_MSG(m_staMac,
"UL MU CS is only performed by non-AP STAs");
2158 "No User Info field for STA (" << m_self
2159 <<
") AID=" << m_staMac->GetAssociationId());
2161 std::set<uint8_t> indices;
2165 auto ctsTxVector = GetCtsTxVectorAfterMuRts(trigger, m_staMac->GetAssociationId());
2166 auto bw = ctsTxVector.GetChannelWidth();
2167 indices = m_phy->GetOperatingChannel().GetAll20MHzChannelIndicesInPrimary(bw);
2172 m_phy->GetOperatingChannel().Get20MHzIndicesCoveringRu(userInfoIt->GetRuAllocation(),
2175 return !m_channelAccessManager->GetPer20MHzBusy(indices);
2185 NS_ASSERT(mpdu->GetHeader().GetAddr1().IsGroup() || mpdu->GetHeader().GetAddr1() == m_self);
2189 if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
2190 m_txTimer.GetReason() == WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF)
2193 NS_ASSERT(m_txParams.m_acknowledgment &&
2194 m_txParams.m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
2195 auto acknowledgment =
static_cast<WifiUlMuMultiStaBa*
>(m_txParams.m_acknowledgment.get());
2198 if (m_txTimer.GetStasExpectedToRespond().count(sender) == 0)
2200 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2206 NS_LOG_DEBUG(
"Received a BlockAckReq in a TB PPDU from " << sender);
2209 mpdu->GetPacket()->PeekHeader(blockAckReq);
2212 GetBaManager(tid)->NotifyGotBlockAckRequest(
2213 m_mac->GetMldAddress(sender).value_or(sender),
2218 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, tid), index);
2219 acknowledgment->baType.m_bitmapLen.push_back(
2220 m_mac->GetBaTypeAsRecipient(sender, tid).m_bitmapLen.at(0));
2222 m_muSnrTag.Set(staId, rxSignalInfo.
snr);
2226 NS_LOG_DEBUG(
"Received an S-MPDU in a TB PPDU from " << sender <<
" (" << *mpdu <<
")");
2229 GetBaManager(tid)->NotifyGotMpdu(mpdu);
2232 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, tid), index);
2233 acknowledgment->baType.m_bitmapLen.push_back(0);
2235 m_muSnrTag.Set(staId, rxSignalInfo.
snr);
2244 VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
2249 if (!acknowledgment->stationsReceivingMultiStaBa.empty() && !m_multiStaBaEvent.IsRunning())
2251 m_multiStaBaEvent = Simulator::Schedule(m_phy->GetSifs(),
2252 &HeFrameExchangeManager::SendMultiStaBlockAck,
2254 std::cref(m_txParams),
2255 mpdu->GetHeader().GetDuration());
2259 m_txTimer.GotResponseFrom(sender);
2261 if (m_txTimer.GetStasExpectedToRespond().empty())
2265 m_channelAccessManager->NotifyAckTimeoutResetNow();
2267 if (!m_multiStaBaEvent.IsRunning())
2272 m_edca->ResetCw(m_linkId);
2273 TransmissionSucceeded();
2281 if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
2282 m_txTimer.GetReason() == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF &&
2285 const auto& sender = hdr.
GetAddr2();
2287 if (m_txTimer.GetStasExpectedToRespond().count(sender) == 0)
2289 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2294 NS_LOG_WARN(
"No QoS Null frame in the received MPDU");
2298 NS_LOG_DEBUG(
"Received a QoS Null frame in a TB PPDU from " << sender);
2301 m_txTimer.GotResponseFrom(sender);
2303 if (m_txTimer.GetStasExpectedToRespond().empty())
2307 m_channelAccessManager->NotifyAckTimeoutResetNow();
2311 m_edca->ResetCw(m_linkId);
2312 TransmissionSucceeded();
2321 if (hdr.
IsCts() && m_txTimer.IsRunning() &&
2322 m_txTimer.GetReason() == WifiTxTimer::WAIT_CTS && m_psduMap.size() == 1)
2327 Mac48Address sender = m_psduMap.begin()->second->GetAddr1();
2331 mpdu->GetPacket()->PeekPacketTag(tag);
2332 GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
2333 GetWifiRemoteStationManager()->ReportRtsOk(m_psduMap.begin()->second->GetHeader(0),
2339 m_channelAccessManager->NotifyCtsTimeoutResetNow();
2340 Simulator::Schedule(m_phy->GetSifs(),
2341 &HeFrameExchangeManager::ProtectionCompleted,
2344 else if (hdr.
IsCts() && m_txTimer.IsRunning() &&
2345 m_txTimer.GetReason() == WifiTxTimer::WAIT_CTS_AFTER_MU_RTS)
2350 NS_LOG_DEBUG(
"Received a CTS frame in response to an MU-RTS");
2353 m_channelAccessManager->NotifyCtsTimeoutResetNow();
2354 Simulator::Schedule(m_phy->GetSifs(),
2355 &HeFrameExchangeManager::ProtectionCompleted,
2358 else if (hdr.
IsAck() && m_txTimer.IsRunning() &&
2359 m_txTimer.GetReason() == WifiTxTimer::WAIT_NORMAL_ACK_AFTER_DL_MU_PPDU)
2363 NS_ASSERT(m_txParams.m_acknowledgment->method ==
2364 WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE);
2366 auto acknowledgment =
2368 NS_ASSERT(acknowledgment->stationsReplyingWithNormalAck.size() == 1);
2370 uint16_t staId = m_apMac->GetAssociationId(
2371 acknowledgment->stationsReplyingWithNormalAck.begin()->first,
2373 auto it = m_psduMap.find(staId);
2376 acknowledgment->stationsReplyingWithNormalAck.begin()->first);
2378 mpdu->GetPacket()->PeekPacketTag(tag);
2379 ReceivedNormalAck(*it->second->begin(),
2380 m_txParams.m_txVector,
2393 m_txTimer.GetReason() == WifiTxTimer::WAIT_BLOCK_ACKS_IN_TB_PPDU)
2396 NS_LOG_DEBUG(
"Received BlockAck in TB PPDU from=" << sender);
2399 mpdu->GetPacket()->PeekPacketTag(tag);
2403 mpdu->GetPacket()->PeekHeader(blockAck);
2405 std::pair<uint16_t, uint16_t> ret =
2406 GetBaManager(tid)->NotifyGotBlockAck(m_linkId,
2408 m_mac->GetMldAddress(sender).value_or(sender),
2410 GetWifiRemoteStationManager()->ReportAmpduTxStatus(sender,
2415 m_txParams.m_txVector);
2418 if (m_txTimer.GetStasExpectedToRespond().count(sender) == 0)
2420 NS_LOG_WARN(
"Received a BlockAck from an unexpected stations: " << sender);
2424 m_txTimer.GotResponseFrom(sender);
2426 if (m_txTimer.GetStasExpectedToRespond().empty())
2430 m_channelAccessManager->NotifyAckTimeoutResetNow();
2434 m_triggerFrame =
nullptr;
2437 m_edca->ResetCw(m_linkId);
2439 TransmissionSucceeded();
2442 else if (hdr.
IsBlockAck() && m_txTimer.IsRunning() &&
2443 m_txTimer.GetReason() == WifiTxTimer::WAIT_BLOCK_ACK_AFTER_TB_PPDU)
2446 mpdu->GetPacket()->PeekHeader(blockAck);
2449 "A Multi-STA BlockAck is expected after a TB PPDU");
2452 NS_ASSERT(m_staMac && m_staMac->IsAssociated());
2455 NS_LOG_DEBUG(
"The sender is not the AP we are associated with");
2459 uint16_t staId = m_staMac->GetAssociationId();
2462 if (indices.empty())
2464 NS_LOG_DEBUG(
"No Per AID TID Info subfield intended for me");
2469 mpdu->GetPacket()->PeekPacketTag(tag);
2472 for (
const auto& index : indices)
2479 NS_ABORT_IF(m_psduMap.empty() || m_psduMap.begin()->first != staId);
2480 GetBaManager(tid)->NotifyGotAck(m_linkId, *m_psduMap.at(staId)->begin());
2489 NS_ABORT_IF(m_psduMap.empty() || m_psduMap.begin()->first != staId);
2490 std::set<uint8_t> tids = m_psduMap.at(staId)->GetTids();
2491 NS_ABORT_MSG_IF(tids.size() > 1,
"Multi-TID A-MPDUs not supported yet");
2492 tid = *tids.begin();
2495 std::pair<uint16_t, uint16_t> ret = GetBaManager(tid)->NotifyGotBlockAck(
2501 GetWifiRemoteStationManager()->ReportAmpduTxStatus(hdr.
GetAddr2(),
2506 m_txParams.m_txVector);
2509 if (m_psduMap.at(staId)->GetHeader(0).IsQosData() &&
2511 || std::any_of(blockAck.
GetBitmap(index).begin(),
2513 [](uint8_t b) { return b != 0; })))
2515 NS_ASSERT(m_psduMap.at(staId)->GetHeader(0).HasData());
2516 NS_ASSERT(m_psduMap.at(staId)->GetHeader(0).GetQosTid() == tid);
2521 m_mac->GetQosTxop(tid)->StartMuEdcaTimerNow(m_linkId);
2527 m_channelAccessManager->NotifyAckTimeoutResetNow();
2529 for (
const auto& [staId, psdu] : m_psduMap)
2531 if (psdu->GetNMpdus() == 1 && psdu->GetHeader(0).IsBlockAckReq())
2538 else if (hdr.
IsBlockAck() && m_txTimer.IsRunning() &&
2539 m_txTimer.GetReason() == WifiTxTimer::WAIT_BLOCK_ACK)
2545 VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
2558 m_triggerFrameInAmpdu =
true;
2563 mpdu->GetPacket()->PeekHeader(trigger);
2574 uint16_t staId = m_staMac->GetAssociationId();
2579 NS_LOG_DEBUG(
"Received MU-RTS Trigger Frame from=" << sender);
2580 GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
2590 Simulator::Schedule(m_phy->GetSifs(),
2591 &HeFrameExchangeManager::SendCtsAfterMuRts,
2600 NS_LOG_DEBUG(
"Received MU-BAR Trigger Frame from=" << sender);
2601 GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
2609 GetBaManager(tid)->NotifyGotBlockAckRequest(
2610 m_mac->GetMldAddress(sender).value_or(sender),
2614 Simulator::Schedule(m_phy->GetSifs(),
2615 &HeFrameExchangeManager::ReceiveMuBarTrigger,
2624 Simulator::Schedule(m_phy->GetSifs(),
2625 &HeFrameExchangeManager::ReceiveBasicTrigger,
2630 else if (trigger.
IsBsrp())
2632 Simulator::Schedule(m_phy->GetSifs(),
2633 &HeFrameExchangeManager::SendQosNullFramesInTbPpdu,
2642 VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
2650 VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
2658 const std::vector<bool>& perMpduStatus)
2660 std::set<uint8_t> tids = psdu->GetTids();
2662 if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
2663 m_txTimer.GetReason() == WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF)
2666 NS_ASSERT(m_txParams.m_acknowledgment &&
2667 m_txParams.m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
2668 auto acknowledgment =
static_cast<WifiUlMuMultiStaBa*
>(m_txParams.m_acknowledgment.get());
2671 if (m_txTimer.GetStasExpectedToRespond().count(sender) == 0)
2673 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2677 NS_LOG_DEBUG(
"Received an A-MPDU in a TB PPDU from " << sender <<
" (" << *psdu <<
")");
2679 if (std::any_of(tids.begin(), tids.end(), [&psdu](uint8_t tid) {
2680 return psdu->GetAckPolicyForTid(tid) == WifiMacHeader::NORMAL_ACK;
2683 if (std::all_of(perMpduStatus.cbegin(), perMpduStatus.cend(), [](
bool v) { return v; }))
2686 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, 14),
2688 acknowledgment->baType.m_bitmapLen.push_back(0);
2694 for (
const auto& tid : tids)
2696 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, tid),
2698 acknowledgment->baType.m_bitmapLen.push_back(
2699 m_mac->GetBaTypeAsRecipient(sender, tid).m_bitmapLen.at(0));
2703 m_muSnrTag.Set(staId, rxSignalInfo.
snr);
2707 if (!acknowledgment->stationsReceivingMultiStaBa.empty() && !m_multiStaBaEvent.IsRunning())
2709 m_multiStaBaEvent = Simulator::Schedule(m_phy->GetSifs(),
2710 &HeFrameExchangeManager::SendMultiStaBlockAck,
2712 std::cref(m_txParams),
2713 psdu->GetDuration());
2717 m_txTimer.GotResponseFrom(sender);
2719 if (m_txTimer.GetStasExpectedToRespond().empty())
2723 m_channelAccessManager->NotifyAckTimeoutResetNow();
2725 if (!m_multiStaBaEvent.IsRunning())
2730 m_edca->ResetCw(m_linkId);
2731 TransmissionSucceeded();
2739 if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
2740 m_txTimer.GetReason() == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF)
2744 if (m_txTimer.GetStasExpectedToRespond().count(sender) == 0)
2746 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2749 if (std::none_of(psdu->begin(), psdu->end(), [](
Ptr<WifiMpdu> mpdu) {
2750 return mpdu->GetHeader().IsQosData() && !mpdu->GetHeader().HasData();
2753 NS_LOG_WARN(
"No QoS Null frame in the received PSDU");
2757 NS_LOG_DEBUG(
"Received QoS Null frames in a TB PPDU from " << sender);
2760 m_txTimer.GotResponseFrom(sender);
2762 if (m_txTimer.GetStasExpectedToRespond().empty())
2766 m_channelAccessManager->NotifyAckTimeoutResetNow();
2770 m_edca->ResetCw(m_linkId);
2771 TransmissionSucceeded();
2778 if (m_triggerFrameInAmpdu)
2781 auto psduIt = psdu->begin();
2782 while (psduIt != psdu->end())
2784 if ((*psduIt)->GetHeader().IsTrigger())
2786 ReceiveMpdu(*psduIt, rxSignalInfo, txVector,
false);
2791 m_triggerFrameInAmpdu =
false;
2796 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
uint16_t GetSupportedBaBufferSize() const override
Get the maximum supported buffer size for a Block Ack agreement.
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)
void ReportFinalRtsFailed(const WifiMacHeader &header)
Should be invoked after calling ReportRtsFailed if NeedRetransmission returns false.
void ReportRtsFailed(const WifiMacHeader &header)
Should be invoked whenever the RtsTimeout associated to a transmission attempt expires.
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.