16#include "ns3/ap-wifi-mac.h"
17#include "ns3/erp-ofdm-phy.h"
19#include "ns3/recipient-block-ack-agreement.h"
20#include "ns3/snr-tag.h"
21#include "ns3/sta-wifi-mac.h"
22#include "ns3/wifi-mac-queue.h"
23#include "ns3/wifi-mac-trailer.h"
28#undef NS_LOG_APPEND_CONTEXT
29#define NS_LOG_APPEND_CONTEXT WIFI_FEM_NS_LOG_APPEND_CONTEXT
41 return psduMap.size() == 1 && psduMap.cbegin()->first ==
SU_STA_ID &&
42 psduMap.cbegin()->second->GetNMpdus() == 1 &&
43 psduMap.cbegin()->second->GetHeader(0).IsTrigger();
49 return psduMap.size() == 1 && psduMap.cbegin()->first ==
SU_STA_ID &&
50 psduMap.cbegin()->second->GetNMpdus() == 1 &&
51 psduMap.cbegin()->second->GetHeader(0).IsTrigger();
57 static TypeId tid =
TypeId(
"ns3::HeFrameExchangeManager")
59 .AddConstructor<HeFrameExchangeManager>()
60 .SetGroupName(
"Wifi");
65 : m_intraBssNavEnd(0),
66 m_triggerFrameInAmpdu(false)
124 "A Multi-User Scheduler can only be aggregated to an HE AP");
145 (!(mpdu = edca->PeekNextMpdu(
m_linkId)) ||
146 (mpdu->GetHeader().IsQosData() && !mpdu->GetHeader().GetAddr1().IsGroup() &&
147 m_mac->GetBaAgreementEstablishedAsOriginator(mpdu->GetHeader().GetAddr1(),
148 mpdu->GetHeader().GetQosTid()))))
167 "The Multi-user Scheduler returned DL_MU_TX with empty psduMap, do not transmit");
218 <<
") incompatible with Basic Trigger Frame");
222 <<
") incompatible with BSRP Trigger Frame");
224 auto txVector = trigger.GetHeTbTxVector(trigger.begin()->GetAid12());
241 if (mpdu->IsQueued())
258 "Cannot use RTS/CTS with MU PPDUs");
283 for (
const auto& userInfo : protection->muRts)
285 const auto addressIt = aidAddrMap.find(userInfo.GetAid12());
286 NS_ASSERT_MSG(addressIt != aidAddrMap.end(),
"AID not found");
311 NS_LOG_FUNCTION(
this << muRtsSize << muRtsTxVector << txDuration << response);
346 protection->muRts.SetCsRequired(
true);
348 payload->AddHeader(protection->muRts);
354 mpdu->GetHeader().SetDuration(
356 protection->muRtsTxVector,
369 protection->muRtsTxVector,
381 protection->muRtsTxVector);
414 if (mpdu->IsQueued())
422 const auto& hdr =
m_psduMap.cbegin()->second->GetHeader(0);
423 if (!hdr.GetAddr1().IsGroup())
428 if (!hdr.GetAddr1().IsGroup() &&
456 for (
const auto& [staId, psdu] :
m_psduMap)
467 auto it = std::find_if(
470 [&to](std::pair<uint16_t,
Ptr<WifiPsdu>> psdu) { return psdu.second->GetAddr1() == to; });
471 if (it != psduMap.end())
506 NS_LOG_DEBUG(address <<
" did not respond, hence it is no longer protected");
526 std::set<Mac48Address> staExpectResponseFrom;
535 auto acknowledgment =
541 if (acknowledgment->stationsSendBlockAckReqTo.contains(psdu.second->GetAddr1()))
544 std::set<uint8_t> tids = psdu.second->GetTids();
546 "Acknowledgment method incompatible with a Multi-TID A-MPDU");
547 uint8_t tid = *tids.begin();
551 m_mac->GetQosTxop(tid)->PrepareBlockAckRequest(psdu.second->GetAddr1(), tid);
556 if (!acknowledgment->stationsReplyingWithNormalAck.empty())
561 &acknowledgment->stationsReplyingWithNormalAck.begin()->second.ackTxVector;
562 auto from = acknowledgment->stationsReplyingWithNormalAck.begin()->first;
565 mpdu = *psdu->begin();
566 staExpectResponseFrom.insert(from);
568 else if (!acknowledgment->stationsReplyingWithBlockAck.empty())
573 &acknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
574 auto from = acknowledgment->stationsReplyingWithBlockAck.begin()->first;
576 staExpectResponseFrom.insert(from);
592 std::map<uint16_t, CtrlBAckRequestHeader> recipients;
594 NS_ASSERT(!acknowledgment->stationsReplyingWithBlockAck.empty());
595 auto staIt = acknowledgment->stationsReplyingWithBlockAck.begin();
597 while (staIt != acknowledgment->stationsReplyingWithBlockAck.end())
603 staIt->second.blockAckTxVector.GetHeMuUserInfo(staId));
604 recipients.emplace(staId, staIt->second.barHeader);
619 for (
auto& station : acknowledgment->stationsReplyingWithBlockAck)
621 staExpectResponseFrom.insert(station.first);
626 acknowledgment->muBarTxVector,
629 *acknowledgment->acknowledgmentTime -= (
m_phy->
GetSifs() + txDuration);
633 &acknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
639 staExpectResponseFrom,
643 staExpectResponseFrom.size());
664 acknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
667 for (
auto& station : acknowledgment->stationsReplyingWithBlockAck)
669 staExpectResponseFrom.insert(station.first);
672 auto psduMapIt = std::find_if(
m_psduMap.begin(),
675 return psdu.second->GetAddr1() == station.first;
680 std::vector<Ptr<WifiMpdu>> mpduList(psduMapIt->second->begin(),
681 psduMapIt->second->end());
682 NS_ASSERT(mpduList.size() == psduMapIt->second->GetNMpdus());
685 station.second.blockAckTxVector.SetLength(acknowledgment->ulLength);
686 mpduList.push_back(
PrepareMuBar(station.second.blockAckTxVector,
687 {{psduMapIt->first, station.second.barHeader}}));
691 station.second.blockAckTxVector.GetHeMuUserInfo(psduMapIt->first));
696 &acknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
706 mpdu = *m_psduMap.begin()->second->begin();
708 auto acknowledgment =
static_cast<WifiUlMuMultiStaBa*
>(m_txParams.m_acknowledgment.get());
711 for (
const auto& station : acknowledgment->stationsReceivingMultiStaBa)
713 staExpectResponseFrom.insert(station.first.first);
719 acknowledgment->baType.m_bitmapLen.clear();
722 responseTxVector = &acknowledgment->tbPpduTxVector;
723 m_trigVector = GetTrigVector(m_muScheduler->GetUlMuInfo(m_linkId).trigger);
729 !m_txParams.m_txVector.IsUlMu() &&
IsTrigger(m_psduMap))
731 CtrlTriggerHeader& trigger = m_muScheduler->GetUlMuInfo(m_linkId).trigger;
736 for (
const auto& userInfo : trigger)
738 auto staIt = m_apMac->GetStaList(m_linkId).find(userInfo.GetAid12());
739 NS_ASSERT(staIt != m_apMac->GetStaList(m_linkId).end());
740 staExpectResponseFrom.insert(staIt->second);
744 txVector = trigger.GetHeTbTxVector(trigger.begin()->GetAid12());
745 responseTxVector = &txVector;
746 m_trigVector = GetTrigVector(m_muScheduler->GetUlMuInfo(m_linkId).trigger);
751 else if (m_txParams.m_txVector.IsUlMu() &&
756 NS_ASSERT(m_staMac && m_staMac->IsAssociated());
757 auto recv = m_psduMap.begin()->second->GetAddr1();
758 txVector = GetWifiRemoteStationManager()->GetBlockAckTxVector(recv, m_txParams.m_txVector);
759 responseTxVector = &txVector;
760 staExpectResponseFrom.insert(recv);
765 else if (m_txParams.m_txVector.IsUlMu() &&
772 NS_ABORT_MSG(
"Unable to handle the selected acknowledgment method ("
773 << m_txParams.m_acknowledgment.get() <<
")");
778 for (
const auto& psdu : m_psduMap)
780 psduMap.emplace(psdu.first, psdu.second);
784 if (m_txParams.m_txVector.IsUlMu())
787 m_txParams.m_txVector,
788 m_phy->GetPhyBand());
793 m_phy->CalculateTxDuration(psduMap, m_txParams.m_txVector, m_phy->GetPhyBand());
796 Time durationId = GetPsduDurationId(txDuration, m_txParams);
797 for (
auto& psdu : m_psduMap)
799 psdu.second->SetDuration(durationId);
812 else if (!m_txParams.m_txVector.IsUlMu())
819 Time timeout = txDuration + m_phy->GetSifs() + m_phy->GetSlot() +
820 m_phy->CalculatePhyPreambleAndHeaderDuration(*responseTxVector);
821 m_channelAccessManager->NotifyAckTimeoutStartNow(
timeout);
828 m_txTimer.Set(timerType,
830 staExpectResponseFrom,
834 m_txParams.m_txVector);
838 m_txTimer.Set(timerType,
840 staExpectResponseFrom,
844 m_txParams.m_txVector);
847 m_txTimer.Set(timerType,
849 staExpectResponseFrom,
853 staExpectResponseFrom.size());
857 m_txTimer.Set(timerType,
859 staExpectResponseFrom,
863 staExpectResponseFrom.size());
866 m_txTimer.Set(timerType,
868 staExpectResponseFrom,
871 m_psduMap.begin()->second,
872 m_txParams.m_txVector);
881 ForwardPsduMapDown(psduMap, m_txParams.m_txVector);
888 auto hePhy =
StaticCast<HePhy>(m_phy->GetPhyEntity(responseTxVector->GetModulationClass()));
889 hePhy->SetTrigVector(m_trigVector, m_txTimer.GetDelayLeft());
906 auto sigBMode = hePhy->GetSigBMode(txVector);
910 for (
const auto& psdu : psduMap)
912 NS_LOG_DEBUG(
"Transmitting: [STAID=" << psdu.first <<
", " << *psdu.second <<
"]");
915 for (
const auto& [staId, psdu] : psduMap)
917 FinalizeMacHeader(psdu);
918 NotifyTxToEdca(psdu);
922 if (psduMap.size() > 1 || psduMap.begin()->second->IsAggregate() ||
923 psduMap.begin()->second->IsSingle())
928 m_phy->Send(psduMap, txVector);
932HeFrameExchangeManager::PrepareMuBar(
const WifiTxVector& responseTxVector,
933 std::map<uint16_t, CtrlBAckRequestHeader> recipients)
const
940 SetTargetRssi(muBar);
946 for (
auto& userInfo : muBar)
948 auto recipientIt = recipients.find(userInfo.GetAid12());
949 NS_ASSERT(recipientIt != recipients.end());
952 userInfo.SetMuBarTriggerDepUserInfo(recipientIt->second);
956 bar->AddHeader(muBar);
964 rxAddress = Mac48Address::GetBroadcast();
969 rxAddress = m_apMac->GetStaList(m_linkId).at(recipients.begin()->first);
981 return Create<WifiMpdu>(bar, hdr);
990 if (protection->
method == WifiProtection::MU_RTS_CTS)
997 GetCtsTxVectorAfterMuRts(muRtsCtsProtection->muRts,
998 muRtsCtsProtection->muRts.begin()->GetAid12());
1001 muRtsCtsProtection->muRts.GetSerializedSize() + WIFI_MAC_FCS_LENGTH;
1002 muRtsCtsProtection->protectionTime =
1003 m_phy->CalculateTxDuration(muRtsSize,
1004 muRtsCtsProtection->muRtsTxVector,
1005 m_phy->GetPhyBand()) +
1006 m_phy->CalculateTxDuration(
GetCtsSize(), ctsTxVector, m_phy->GetPhyBand()) +
1007 2 * m_phy->GetSifs();
1011 VhtFrameExchangeManager::CalculateProtectionTime(protection);
1024 if (acknowledgment->
method == WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE)
1031 NS_ABORT_IF(dlMuBarBaAcknowledgment->stationsReplyingWithNormalAck.size() +
1032 dlMuBarBaAcknowledgment->stationsReplyingWithBlockAck.size() >
1035 if (!dlMuBarBaAcknowledgment->stationsReplyingWithNormalAck.empty())
1038 dlMuBarBaAcknowledgment->stationsReplyingWithNormalAck.begin()->second;
1041 m_phy->CalculateTxDuration(
GetAckSize(), info.ackTxVector, m_phy->GetPhyBand());
1044 if (!dlMuBarBaAcknowledgment->stationsReplyingWithBlockAck.empty())
1047 dlMuBarBaAcknowledgment->stationsReplyingWithBlockAck.begin()->second;
1048 duration += m_phy->GetSifs() + m_phy->CalculateTxDuration(
GetBlockAckSize(info.baType),
1049 info.blockAckTxVector,
1050 m_phy->GetPhyBand());
1053 for (
const auto& stations : dlMuBarBaAcknowledgment->stationsSendBlockAckReqTo)
1055 const auto& info = stations.second;
1056 duration += m_phy->GetSifs() +
1058 info.blockAckReqTxVector,
1059 m_phy->GetPhyBand()) +
1062 info.blockAckTxVector,
1063 m_phy->GetPhyBand());
1066 dlMuBarBaAcknowledgment->acknowledgmentTime = duration;
1071 else if (acknowledgment->
method == WifiAcknowledgment::DL_MU_TF_MU_BAR)
1073 auto dlMuTfMuBarAcknowledgment =
static_cast<WifiDlMuTfMuBar*
>(acknowledgment);
1077 for (
const auto& stations : dlMuTfMuBarAcknowledgment->stationsReplyingWithBlockAck)
1080 const auto& info = stations.second;
1081 NS_ASSERT(info.blockAckTxVector.GetHeMuUserInfoMap().size() == 1);
1082 uint16_t staId = info.blockAckTxVector.GetHeMuUserInfoMap().begin()->first;
1084 info.blockAckTxVector,
1085 m_phy->GetPhyBand(),
1088 if (currBlockAckDuration > duration)
1090 duration = currBlockAckDuration;
1096 WifiTxVector& txVector = dlMuTfMuBarAcknowledgment->stationsReplyingWithBlockAck.begin()
1097 ->second.blockAckTxVector;
1098 std::tie(dlMuTfMuBarAcknowledgment->ulLength, duration) =
1099 HePhy::ConvertHeTbPpduDurationToLSigLength(duration, txVector, m_phy->GetPhyBand());
1102 if (dlMuTfMuBarAcknowledgment->muBarTxVector.GetModulationClass() >=
WIFI_MOD_CLASS_VHT)
1105 muBarSize = MpduAggregator::GetSizeIfAggregated(muBarSize, 0);
1107 dlMuTfMuBarAcknowledgment->acknowledgmentTime =
1109 m_phy->CalculateTxDuration(muBarSize,
1110 dlMuTfMuBarAcknowledgment->muBarTxVector,
1111 m_phy->GetPhyBand()) +
1112 m_phy->GetSifs() + duration;
1117 else if (acknowledgment->
method == WifiAcknowledgment::DL_MU_AGGREGATE_TF)
1123 for (
const auto& stations : dlMuAggrTfAcknowledgment->stationsReplyingWithBlockAck)
1126 const auto& info = stations.second;
1127 NS_ASSERT(info.blockAckTxVector.GetHeMuUserInfoMap().size() == 1);
1128 uint16_t staId = info.blockAckTxVector.GetHeMuUserInfoMap().begin()->first;
1130 info.blockAckTxVector,
1131 m_phy->GetPhyBand(),
1134 if (currBlockAckDuration > duration)
1136 duration = currBlockAckDuration;
1143 dlMuAggrTfAcknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
1144 std::tie(dlMuAggrTfAcknowledgment->ulLength, duration) =
1145 HePhy::ConvertHeTbPpduDurationToLSigLength(duration, txVector, m_phy->GetPhyBand());
1146 dlMuAggrTfAcknowledgment->acknowledgmentTime = m_phy->GetSifs() + duration;
1151 else if (acknowledgment->
method == WifiAcknowledgment::UL_MU_MULTI_STA_BA)
1156 ulMuMultiStaBa->multiStaBaTxVector,
1157 m_phy->GetPhyBand());
1158 ulMuMultiStaBa->acknowledgmentTime = m_phy->GetSifs() + duration;
1163 else if (acknowledgment->
method == WifiAcknowledgment::ACK_AFTER_TB_PPDU)
1172 VhtFrameExchangeManager::CalculateAcknowledgmentTime(acknowledgment);
1177HeFrameExchangeManager::GetCtsModeAfterMuRts()
const
1182 : OfdmPhy::GetOfdmRate6Mbps();
1187 uint16_t staId)
const
1192 NS_ASSERT_MSG(userInfoIt != trigger.
end(),
"User Info field for AID=" << staId <<
" not found");
1195 if (uint8_t ru = userInfoIt->GetMuRtsRuAllocation(); ru < 65)
1213 auto txVector = GetWifiRemoteStationManager()->GetCtsTxVector(m_bssid, GetCtsModeAfterMuRts());
1215 txVector.SetChannelWidth(bw);
1221HeFrameExchangeManager::GetTxDuration(
uint32_t ppduPayloadSize,
1227 return VhtFrameExchangeManager::GetTxDuration(ppduPayloadSize, receiver, txParams);
1234 txParams.
m_acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF)
1238 NS_ASSERT_MSG(psduInfo,
"No information for " << receiver <<
" in TX params");
1239 NS_ASSERT_MSG(!psduInfo->seqNumbers.empty(),
"No sequence number for " << receiver);
1240 const auto tid = psduInfo->seqNumbers.cbegin()->first;
1242 ppduPayloadSize = MpduAggregator::GetSizeIfAggregated(
1243 GetMuBarSize({m_mac->GetBarTypeAsOriginator(receiver, tid)}),
1247 uint16_t staId = (txParams.
m_txVector.
IsDlMu() ? m_apMac->GetAssociationId(receiver, m_linkId)
1248 : m_staMac->GetAssociationId());
1249 Time psduDuration = m_phy->CalculateTxDuration(ppduPayloadSize,
1251 m_phy->GetPhyBand(),
1258HeFrameExchangeManager::TbPpduTimeout(
WifiPsduMap* psduMap, std::size_t nSolicitedStations)
1260 const auto& staMissedTbPpduFrom = m_txTimer.GetStasExpectedToRespond();
1261 NS_LOG_FUNCTION(
this << psduMap << staMissedTbPpduFrom.size() << nSolicitedStations);
1267 NS_ASSERT(!staMissedTbPpduFrom.empty());
1270 if (staMissedTbPpduFrom.size() == nSolicitedStations)
1273 m_edca->UpdateFailedCw(m_linkId);
1275 TransmissionFailed();
1277 else if (!m_multiStaBaEvent.IsPending())
1279 m_edca->ResetCw(m_linkId);
1280 TransmissionSucceeded();
1288 std::size_t nSolicitedStations)
1293 NS_ASSERT(m_txParams.m_acknowledgment &&
1294 (m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF ||
1295 m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_TF_MU_BAR));
1298 const auto& staMissedBlockAckFrom = m_txTimer.GetStasExpectedToRespond();
1299 NS_ASSERT(!staMissedBlockAckFrom.empty());
1303 if (staMissedBlockAckFrom.size() == nSolicitedStations)
1307 GetWifiRemoteStationManager()->ReportDataFailed(*psduMap->begin()->second->begin());
1319 m_triggerFrame =
nullptr;
1322 for (
const auto& sta : staMissedBlockAckFrom)
1331 MissedBlockAck(psdu, m_txParams.m_txVector, psduResetCw);
1332 resetCw = resetCw || psduResetCw;
1339 m_edca->ResetCw(m_linkId);
1343 m_edca->UpdateFailedCw(m_linkId);
1346 if (staMissedBlockAckFrom.size() == nSolicitedStations)
1349 TransmissionFailed();
1353 TransmissionSucceeded();
1366 GetWifiRemoteStationManager()->ReportDataFailed(*psdu->begin());
1368 MissedBlockAck(psdu, m_txParams.m_txVector, resetCw);
1383 VhtFrameExchangeManager::NormalAckTimeout(mpdu, txVector);
1388 for (
auto& psdu : m_psduMap)
1392 if (mpdu->IsQueued())
1394 m_mac->GetTxopQueue(mpdu->GetQueueAc())->GetOriginal(mpdu)->GetHeader().SetRetry();
1395 mpdu->ResetInFlight(m_linkId);
1407 VhtFrameExchangeManager::BlockAckTimeout(psdu, txVector);
1412 for (
auto& psdu : m_psduMap)
1416 if (mpdu->IsQueued())
1418 mpdu->GetHeader().SetRetry();
1434 for (
const auto& userInfoField : trigger)
1437 userInfoField.GetAid12(),
1438 {userInfoField.GetRuAllocation(), userInfoField.GetUlMcs(), userInfoField.GetNss()});
1450 uint16_t staId = m_staMac->GetAssociationId();
1457 NS_ASSERT_MSG(heConfiguration,
"This STA has to be an HE station to send an HE TB PPDU");
1460 if (userInfoIt->IsUlTargetRssiMaxTxPower())
1462 NS_LOG_LOGIC(
"AP requested using the max transmit power (" << m_phy->GetTxPowerEnd()
1468 uint8_t powerLevel = GetWifiRemoteStationManager()->GetDefaultTxPowerLevel();
1486 auto optRssi = GetMostRecentRssi(triggerSender);
1492 auto reqTxPower =
static_cast<dBm_u>(userInfoIt->GetUlTargetRssi() + pathLossDb);
1495 uint8_t numPowerLevels = m_phy->GetNTxPower();
1496 if (numPowerLevels > 1)
1498 dBm_u step = (m_phy->GetTxPowerEnd() - m_phy->GetTxPowerStart()) / (numPowerLevels - 1);
1499 powerLevel =
static_cast<uint8_t
>(
1500 ceil((reqTxPower - m_phy->GetTxPowerStart()) /
1502 if (powerLevel > numPowerLevels)
1504 powerLevel = numPowerLevels;
1507 if (reqTxPower > m_phy->GetPower(powerLevel))
1509 NS_LOG_WARN(
"The requested power level (" << reqTxPower <<
"dBm) cannot be satisfied (max: "
1510 << m_phy->GetTxPowerEnd() <<
"dBm)");
1514 <<
"input {pathLoss=" << pathLossDb <<
"dB, reqTxPower=" << reqTxPower <<
"dBm}"
1515 <<
" output {powerLevel=" << +powerLevel <<
" -> " << m_phy->GetPower(powerLevel)
1517 <<
" PHY power capa {min=" << m_phy->GetTxPowerStart() <<
"dBm, max="
1518 << m_phy->GetTxPowerEnd() <<
"dBm, levels:" << +numPowerLevels <<
"}");
1524HeFrameExchangeManager::GetMostRecentRssi(
const Mac48Address& address)
const
1526 return GetWifiRemoteStationManager()->GetMostRecentRssi(address);
1536 m_phy->GetPower(GetWifiRemoteStationManager()->GetDefaultTxPowerLevel())));
1537 for (
auto& userInfo : trigger)
1539 const auto staList = m_apMac->GetStaList(m_linkId);
1540 auto itAidAddr = staList.find(userInfo.GetAid12());
1542 auto optRssi = GetMostRecentRssi(itAidAddr->second);
1544 auto rssi =
static_cast<int8_t>(*optRssi);
1545 rssi = (rssi >= -20)
1547 : ((rssi <= -110) ? -110 : rssi);
1548 userInfo.SetUlTargetRssi(rssi);
1557 auto txVectorCopy = txVector;
1559 if (psdu->GetNMpdus() == 1 && psdu->GetHeader(0).IsTrigger())
1562 psdu->GetPayload(0)->PeekHeader(trigger);
1576 if (m_staMac !=
nullptr && m_staMac->IsAssociated() &&
1587 psdu = Create<const WifiPsdu>(Create<Packet>(), rts);
1591 GetWifiRemoteStationManager()->GetCtsTxVector(m_bssid, GetCtsModeAfterMuRts());
1594 VhtFrameExchangeManager::PostProcessFrame(psdu, txVectorCopy);
1604 if (!UlMuCsMediumIdle(trigger))
1606 NS_LOG_DEBUG(
"UL MU CS indicated medium busy, cannot send CTS");
1610 NS_ASSERT(m_staMac !=
nullptr && m_staMac->IsAssociated());
1611 WifiTxVector ctsTxVector = GetCtsTxVectorAfterMuRts(trigger, m_staMac->GetAssociationId());
1614 DoSendCtsAfterRts(muRtsHdr, ctsTxVector, muRtsSnr);
1624 txParams.
m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
1627 NS_ASSERT(!acknowledgment->stationsReceivingMultiStaBa.empty());
1630 blockAck.
SetType(acknowledgment->baType);
1634 for (
const auto& staInfo : acknowledgment->stationsReceivingMultiStaBa)
1636 receiver = staInfo.first.first;
1637 uint8_t tid = staInfo.first.second;
1638 std::size_t index = staInfo.second;
1640 blockAck.
SetAid11(m_apMac->GetAssociationId(receiver, m_linkId), index);
1646 NS_LOG_DEBUG(
"Multi-STA Block Ack: Sending All-ack to=" << receiver);
1651 if (acknowledgment->baType.m_bitmapLen.at(index) == 0)
1654 NS_LOG_DEBUG(
"Multi-STA Block Ack: Sending Ack to=" << receiver);
1662 auto agreement = m_mac->GetBaAgreementEstablishedAsRecipient(receiver, tid);
1664 agreement->get().FillBlockAckBitmap(&blockAck, index);
1665 NS_LOG_DEBUG(
"Multi-STA Block Ack: Sending Block Ack with seq="
1667 <<
" tid=" << +tid);
1673 hdr.
SetAddr1(acknowledgment->stationsReceivingMultiStaBa.size() == 1
1675 : Mac48Address::GetBroadcast());
1681 packet->AddHeader(blockAck);
1683 GetWifiPsdu(Create<WifiMpdu>(packet, hdr), acknowledgment->multiStaBaTxVector);
1686 acknowledgment->multiStaBaTxVector,
1687 m_phy->GetPhyBand());
1699 if (m_edca->GetTxopLimit(m_linkId).IsZero())
1702 psdu->SetDuration(
Max(durationId - m_phy->GetSifs() - txDuration,
Seconds(0)));
1707 psdu->SetDuration(
Max(m_edca->GetRemainingTxop(m_linkId) - txDuration,
Seconds(0)));
1710 psdu->GetPayload(0)->AddPacketTag(m_muSnrTag);
1712 ForwardPsduDown(psdu, acknowledgment->multiStaBaTxVector);
1716 m_edca->ResetCw(m_linkId);
1718 Simulator::Schedule(txDuration, &HeFrameExchangeManager::TransmissionSucceeded,
this);
1727 NS_ASSERT(m_staMac && m_staMac->IsAssociated());
1729 NS_LOG_DEBUG(
"Received a Trigger Frame (basic variant) soliciting a transmission");
1731 if (!UlMuCsMediumIdle(trigger))
1742 std::vector<uint8_t> tids;
1743 uint16_t staId = m_staMac->GetAssociationId();
1746 for (uint8_t i = 0; i < 4; i++)
1749 tids.push_back(acIt->second.GetHighTid());
1750 tids.push_back(acIt->second.GetLowTid());
1762 Time ppduDuration = HePhy::ConvertLSigLengthToHeTbPpduDuration(trigger.
GetUlLength(),
1764 m_phy->GetPhyBand());
1766 for (
const auto& tid : tids)
1770 if (!m_mac->GetBaAgreementEstablishedAsOriginator(hdr.
GetAddr2(), tid))
1780 if (
auto mpdu = GetBar(edca->GetAccessCategory(), tid, hdr.
GetAddr2());
1781 mpdu && TryAddMpdu(mpdu, txParams, ppduDuration))
1784 psdu = Create<WifiPsdu>(mpdu,
true);
1790 GetWifiRemoteStationManager()->GetMldAddress(hdr.
GetAddr2()).value_or(hdr.
GetAddr2());
1791 if (
auto mpdu = edca->PeekNextMpdu(m_linkId, tid, receiver))
1793 mpdu = CreateAliasIfNeeded(mpdu);
1794 if (
auto item = edca->GetNextMpdu(m_linkId, mpdu, txParams, ppduDuration,
false))
1797 std::vector<Ptr<WifiMpdu>> mpduList =
1798 m_mpduAggregator->GetNextAmpdu(item, txParams, ppduDuration);
1799 psdu = (mpduList.size() > 1 ? Create<WifiPsdu>(std::move(mpduList))
1800 : Create<WifiPsdu>(item,
true));
1808 psdu->SetDuration(hdr.
GetDuration() - m_phy->GetSifs() - ppduDuration);
1809 SendPsduMapWithProtection(
WifiPsduMap{{staId, psdu}}, txParams);
1814 SendQosNullFramesInTbPpdu(trigger, hdr);
1824 NS_ASSERT(m_staMac && m_staMac->IsAssociated());
1828 if (!UlMuCsMediumIdle(trigger))
1834 GetWifiRemoteStationManager()->GetMldAddress(hdr.
GetAddr2()).value_or(hdr.
GetAddr2());
1837 header.
SetAddr2(m_mac->GetAddress());
1852 Time ppduDuration = HePhy::ConvertLSigLengthToHeTbPpduDuration(trigger.
GetUlLength(),
1854 m_phy->GetPhyBand());
1857 std::vector<Ptr<WifiMpdu>> mpduList;
1859 for (uint8_t tid = 0; tid < 8; ++tid)
1861 if (!m_mac->GetBaAgreementEstablishedAsOriginator(hdr.
GetAddr2(), tid))
1863 NS_LOG_DEBUG(
"Skipping tid=" << +tid <<
" because no agreement established");
1873 auto mpdu = Create<WifiMpdu>(Create<Packet>(), header);
1874 mpdu = CreateAliasIfNeeded(mpdu);
1876 UpdateTxDuration(header.
GetAddr1(), txParams);
1887 NS_LOG_DEBUG(
"Aggregating a QoS Null frame with tid=" << +tid);
1889 mpduList.push_back(mpdu);
1892 if (mpduList.empty())
1894 NS_LOG_DEBUG(
"Not enough time to send a QoS Null frame");
1898 Ptr<WifiPsdu> psdu = (mpduList.size() > 1 ? Create<WifiPsdu>(std::move(mpduList))
1899 : Create<WifiPsdu>(mpduList.front(),
true));
1900 uint16_t staId = m_staMac->GetAssociationId();
1901 SendPsduMapWithProtection(
WifiPsduMap{{staId, psdu}}, txParams);
1912 auto agreement = m_mac->GetBaAgreementEstablishedAsRecipient(m_bssid, tid);
1916 NS_LOG_DEBUG(
"There's not a valid agreement for this BlockAckReq");
1920 if (!UlMuCsMediumIdle(trigger))
1926 auto txVector = GetHeTbTxVector(trigger, m_bssid);
1927 SendBlockAck(*agreement, durationId, txVector, snr);
1941 const auto ra = psdu->GetAddr1();
1942 const auto ta = psdu->GetAddr2();
1943 const auto bssid = psdu->GetHeader(0).GetAddr3();
1946 if (ra == m_bssid || ta == m_bssid || bssid == m_bssid)
1954 if (psdu->GetHeader(0).IsCtl() && ta == empty && ra == m_txopHolder)
1968 if (bssid != empty && bssid != m_bssid)
1976 if (bssid == empty && ta != empty && ra != empty && ta != m_bssid && ra != m_bssid)
1989 const auto bssColor = m_mac->GetHeConfiguration()->GetBssColor();
1992 return bssColor != 0 && bssColor == txVector.
GetBssColor();
2000 if (!psdu->HasNav())
2005 if (psdu->GetAddr1() == m_self)
2015 if (!IsIntraBssPpdu(psdu, txVector))
2017 NS_LOG_DEBUG(
"PPDU not classified as intra-BSS, update the basic NAV");
2018 VhtFrameExchangeManager::UpdateNav(psdu, txVector);
2022 NS_LOG_DEBUG(
"PPDU classified as intra-BSS, update the intra-BSS NAV");
2023 Time duration = psdu->GetDuration();
2026 if (psdu->GetHeader(0).IsCfEnd())
2032 NS_LOG_DEBUG(
"Received CF-End, resetting the intra-BSS NAV");
2033 IntraBssNavResetTimeout();
2039 auto intraBssNavEnd = Simulator::Now() + duration;
2040 if (intraBssNavEnd > m_intraBssNavEnd)
2042 m_intraBssNavEnd = intraBssNavEnd;
2043 NS_LOG_DEBUG(
"Updated intra-BSS NAV=" << m_intraBssNavEnd);
2054 if (psdu->GetHeader(0).IsRts())
2057 GetWifiRemoteStationManager()->GetCtsTxVector(psdu->GetAddr2(), txVector.
GetMode());
2058 auto navResetDelay =
2059 2 * m_phy->GetSifs() +
2060 WifiPhy::CalculateTxDuration(
GetCtsSize(), ctsTxVector, m_phy->GetPhyBand()) +
2061 m_phy->CalculatePhyPreambleAndHeaderDuration(ctsTxVector) + 2 * m_phy->GetSlot();
2062 m_intraBssNavResetEvent =
2063 Simulator::Schedule(navResetDelay,
2064 &HeFrameExchangeManager::IntraBssNavResetTimeout,
2068 NS_LOG_DEBUG(
"Current intra-BSS NAV=" << m_intraBssNavEnd);
2070 m_channelAccessManager->NotifyNavStartNow(duration);
2074HeFrameExchangeManager::ClearTxopHolderIfNeeded()
2077 if (m_intraBssNavEnd <= Simulator::Now())
2079 m_txopHolder.reset();
2084HeFrameExchangeManager::NavResetTimeout()
2087 m_navEnd = Simulator::Now();
2090 Time intraBssNav = Simulator::GetDelayLeft(m_intraBssNavResetEvent);
2091 m_channelAccessManager->NotifyNavResetNow(intraBssNav);
2095HeFrameExchangeManager::IntraBssNavResetTimeout()
2098 m_intraBssNavEnd = Simulator::Now();
2099 ClearTxopHolderIfNeeded();
2101 Time basicNav = Simulator::GetDelayLeft(m_navResetEvent);
2102 m_channelAccessManager->NotifyNavResetNow(basicNav);
2105std::optional<Mac48Address>
2116 return VhtFrameExchangeManager::FindTxopHolder(hdr, txVector);
2118 return std::nullopt;
2122HeFrameExchangeManager::VirtualCsMediumIdle()
const
2127 return m_navEnd <= Simulator::Now() && m_intraBssNavEnd <= Simulator::Now();
2143 const Time now = Simulator::Now();
2150 NS_ASSERT_MSG(m_staMac,
"UL MU CS is only performed by non-AP STAs");
2153 "No User Info field for STA (" << m_self
2154 <<
") AID=" << m_staMac->GetAssociationId());
2156 std::set<uint8_t> indices;
2160 auto ctsTxVector = GetCtsTxVectorAfterMuRts(trigger, m_staMac->GetAssociationId());
2161 auto bw = ctsTxVector.GetChannelWidth();
2162 indices = m_phy->GetOperatingChannel().GetAll20MHzChannelIndicesInPrimary(bw);
2167 m_phy->GetOperatingChannel().Get20MHzIndicesCoveringRu(userInfoIt->GetRuAllocation(),
2170 return !m_channelAccessManager->GetPer20MHzBusy(indices);
2180 NS_ASSERT(mpdu->GetHeader().GetAddr1().IsGroup() || mpdu->GetHeader().GetAddr1() == m_self);
2184 if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
2185 m_txTimer.GetReason() == WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF)
2188 NS_ASSERT(m_txParams.m_acknowledgment &&
2189 m_txParams.m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
2190 auto acknowledgment =
static_cast<WifiUlMuMultiStaBa*
>(m_txParams.m_acknowledgment.get());
2193 if (!m_txTimer.GetStasExpectedToRespond().contains(sender))
2195 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2201 NS_LOG_DEBUG(
"Received a BlockAckReq in a TB PPDU from " << sender);
2204 mpdu->GetPacket()->PeekHeader(blockAckReq);
2207 GetBaManager(tid)->NotifyGotBlockAckRequest(
2208 m_mac->GetMldAddress(sender).value_or(sender),
2213 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, tid), index);
2214 acknowledgment->baType.m_bitmapLen.push_back(
2215 m_mac->GetBaTypeAsRecipient(sender, tid).m_bitmapLen.at(0));
2217 m_muSnrTag.Set(staId, rxSignalInfo.
snr);
2221 NS_LOG_DEBUG(
"Received an S-MPDU in a TB PPDU from " << sender <<
" (" << *mpdu <<
")");
2224 GetBaManager(tid)->NotifyGotMpdu(mpdu);
2227 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, tid), index);
2228 acknowledgment->baType.m_bitmapLen.push_back(0);
2230 m_muSnrTag.Set(staId, rxSignalInfo.
snr);
2239 VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
2244 if (!acknowledgment->stationsReceivingMultiStaBa.empty() && !m_multiStaBaEvent.IsPending())
2246 m_multiStaBaEvent = Simulator::Schedule(m_phy->GetSifs(),
2247 &HeFrameExchangeManager::SendMultiStaBlockAck,
2249 std::cref(m_txParams),
2250 mpdu->GetHeader().GetDuration());
2254 m_txTimer.GotResponseFrom(sender);
2256 if (m_txTimer.GetStasExpectedToRespond().empty())
2260 m_channelAccessManager->NotifyAckTimeoutResetNow();
2262 if (!m_multiStaBaEvent.IsPending())
2267 m_edca->ResetCw(m_linkId);
2268 TransmissionSucceeded();
2276 if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
2277 m_txTimer.GetReason() == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF &&
2280 const auto& sender = hdr.
GetAddr2();
2282 if (!m_txTimer.GetStasExpectedToRespond().contains(sender))
2284 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2289 NS_LOG_WARN(
"No QoS Null frame in the received MPDU");
2293 NS_LOG_DEBUG(
"Received a QoS Null frame in a TB PPDU from " << sender);
2296 m_txTimer.GotResponseFrom(sender);
2298 if (m_txTimer.GetStasExpectedToRespond().empty())
2302 m_channelAccessManager->NotifyAckTimeoutResetNow();
2306 m_edca->ResetCw(m_linkId);
2307 TransmissionSucceeded();
2316 if (hdr.
IsCts() && m_txTimer.IsRunning() &&
2317 m_txTimer.GetReason() == WifiTxTimer::WAIT_CTS && m_psduMap.size() == 1)
2322 Mac48Address sender = m_psduMap.begin()->second->GetAddr1();
2326 mpdu->GetPacket()->PeekPacketTag(tag);
2327 GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
2328 GetWifiRemoteStationManager()->ReportRtsOk(m_psduMap.begin()->second->GetHeader(0),
2334 m_channelAccessManager->NotifyCtsTimeoutResetNow();
2335 Simulator::Schedule(m_phy->GetSifs(),
2336 &HeFrameExchangeManager::ProtectionCompleted,
2339 else if (hdr.
IsCts() && m_txTimer.IsRunning() &&
2340 m_txTimer.GetReason() == WifiTxTimer::WAIT_CTS_AFTER_MU_RTS)
2345 NS_LOG_DEBUG(
"Received a CTS frame in response to an MU-RTS");
2348 m_channelAccessManager->NotifyCtsTimeoutResetNow();
2349 Simulator::Schedule(m_phy->GetSifs(),
2350 &HeFrameExchangeManager::ProtectionCompleted,
2353 else if (hdr.
IsAck() && m_txTimer.IsRunning() &&
2354 m_txTimer.GetReason() == WifiTxTimer::WAIT_NORMAL_ACK_AFTER_DL_MU_PPDU)
2358 NS_ASSERT(m_txParams.m_acknowledgment->method ==
2359 WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE);
2361 auto acknowledgment =
2363 NS_ASSERT(acknowledgment->stationsReplyingWithNormalAck.size() == 1);
2365 uint16_t staId = m_apMac->GetAssociationId(
2366 acknowledgment->stationsReplyingWithNormalAck.begin()->first,
2368 auto it = m_psduMap.find(staId);
2371 acknowledgment->stationsReplyingWithNormalAck.begin()->first);
2373 mpdu->GetPacket()->PeekPacketTag(tag);
2374 ReceivedNormalAck(*it->second->begin(),
2375 m_txParams.m_txVector,
2388 m_txTimer.GetReason() == WifiTxTimer::WAIT_BLOCK_ACKS_IN_TB_PPDU)
2391 NS_LOG_DEBUG(
"Received BlockAck in TB PPDU from=" << sender);
2394 mpdu->GetPacket()->PeekPacketTag(tag);
2398 mpdu->GetPacket()->PeekHeader(blockAck);
2400 std::pair<uint16_t, uint16_t> ret =
2401 GetBaManager(tid)->NotifyGotBlockAck(m_linkId,
2403 m_mac->GetMldAddress(sender).value_or(sender),
2405 GetWifiRemoteStationManager()->ReportAmpduTxStatus(sender,
2410 m_txParams.m_txVector);
2413 if (!m_txTimer.GetStasExpectedToRespond().contains(sender))
2415 NS_LOG_WARN(
"Received a BlockAck from an unexpected stations: " << sender);
2419 m_txTimer.GotResponseFrom(sender);
2421 if (m_txTimer.GetStasExpectedToRespond().empty())
2425 m_channelAccessManager->NotifyAckTimeoutResetNow();
2429 m_triggerFrame =
nullptr;
2432 m_edca->ResetCw(m_linkId);
2434 TransmissionSucceeded();
2437 else if (hdr.
IsBlockAck() && m_txTimer.IsRunning() &&
2438 m_txTimer.GetReason() == WifiTxTimer::WAIT_BLOCK_ACK_AFTER_TB_PPDU)
2441 mpdu->GetPacket()->PeekHeader(blockAck);
2444 "A Multi-STA BlockAck is expected after a TB PPDU");
2447 NS_ASSERT(m_staMac && m_staMac->IsAssociated());
2450 NS_LOG_DEBUG(
"The sender is not the AP we are associated with");
2454 uint16_t staId = m_staMac->GetAssociationId();
2457 if (indices.empty())
2459 NS_LOG_DEBUG(
"No Per AID TID Info subfield intended for me");
2464 mpdu->GetPacket()->PeekPacketTag(tag);
2467 for (
const auto& index : indices)
2474 NS_ABORT_IF(m_psduMap.empty() || m_psduMap.begin()->first != staId);
2475 GetBaManager(tid)->NotifyGotAck(m_linkId, *m_psduMap.at(staId)->begin());
2484 NS_ABORT_IF(m_psduMap.empty() || m_psduMap.begin()->first != staId);
2485 std::set<uint8_t> tids = m_psduMap.at(staId)->GetTids();
2486 NS_ABORT_MSG_IF(tids.size() > 1,
"Multi-TID A-MPDUs not supported yet");
2487 tid = *tids.begin();
2490 std::pair<uint16_t, uint16_t> ret = GetBaManager(tid)->NotifyGotBlockAck(
2496 GetWifiRemoteStationManager()->ReportAmpduTxStatus(hdr.
GetAddr2(),
2501 m_txParams.m_txVector);
2504 if (m_psduMap.at(staId)->GetHeader(0).IsQosData() &&
2506 || std::any_of(blockAck.
GetBitmap(index).begin(),
2508 [](uint8_t b) { return b != 0; })))
2510 NS_ASSERT(m_psduMap.at(staId)->GetHeader(0).HasData());
2511 NS_ASSERT(m_psduMap.at(staId)->GetHeader(0).GetQosTid() == tid);
2516 m_mac->GetQosTxop(tid)->StartMuEdcaTimerNow(m_linkId);
2522 m_channelAccessManager->NotifyAckTimeoutResetNow();
2524 for (
const auto& [staId, psdu] : m_psduMap)
2526 if (psdu->GetNMpdus() == 1 && psdu->GetHeader(0).IsBlockAckReq())
2533 else if (hdr.
IsBlockAck() && m_txTimer.IsRunning() &&
2534 m_txTimer.GetReason() == WifiTxTimer::WAIT_BLOCK_ACK)
2540 VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
2553 m_triggerFrameInAmpdu =
true;
2558 mpdu->GetPacket()->PeekHeader(trigger);
2569 uint16_t staId = m_staMac->GetAssociationId();
2574 NS_LOG_DEBUG(
"Received MU-RTS Trigger Frame from=" << sender);
2575 GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
2585 Simulator::Schedule(m_phy->GetSifs(),
2586 &HeFrameExchangeManager::SendCtsAfterMuRts,
2595 NS_LOG_DEBUG(
"Received MU-BAR Trigger Frame from=" << sender);
2596 GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
2604 GetBaManager(tid)->NotifyGotBlockAckRequest(
2605 m_mac->GetMldAddress(sender).value_or(sender),
2609 Simulator::Schedule(m_phy->GetSifs(),
2610 &HeFrameExchangeManager::ReceiveMuBarTrigger,
2619 Simulator::Schedule(m_phy->GetSifs(),
2620 &HeFrameExchangeManager::ReceiveBasicTrigger,
2625 else if (trigger.
IsBsrp())
2627 Simulator::Schedule(m_phy->GetSifs(),
2628 &HeFrameExchangeManager::SendQosNullFramesInTbPpdu,
2637 VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
2645 VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
2653 const std::vector<bool>& perMpduStatus)
2655 std::set<uint8_t> tids = psdu->GetTids();
2657 if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
2658 m_txTimer.GetReason() == WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF)
2661 NS_ASSERT(m_txParams.m_acknowledgment &&
2662 m_txParams.m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
2663 auto acknowledgment =
static_cast<WifiUlMuMultiStaBa*
>(m_txParams.m_acknowledgment.get());
2666 if (!m_txTimer.GetStasExpectedToRespond().contains(sender))
2668 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2672 NS_LOG_DEBUG(
"Received an A-MPDU in a TB PPDU from " << sender <<
" (" << *psdu <<
")");
2674 if (std::any_of(tids.begin(), tids.end(), [&psdu](uint8_t tid) {
2675 return psdu->GetAckPolicyForTid(tid) == WifiMacHeader::NORMAL_ACK;
2678 if (std::all_of(perMpduStatus.cbegin(), perMpduStatus.cend(), [](
bool v) { return v; }))
2681 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, 14),
2683 acknowledgment->baType.m_bitmapLen.push_back(0);
2689 for (
const auto& tid : tids)
2691 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, tid),
2693 acknowledgment->baType.m_bitmapLen.push_back(
2694 m_mac->GetBaTypeAsRecipient(sender, tid).m_bitmapLen.at(0));
2698 m_muSnrTag.Set(staId, rxSignalInfo.
snr);
2702 if (!acknowledgment->stationsReceivingMultiStaBa.empty() && !m_multiStaBaEvent.IsPending())
2704 m_multiStaBaEvent = Simulator::Schedule(m_phy->GetSifs(),
2705 &HeFrameExchangeManager::SendMultiStaBlockAck,
2707 std::cref(m_txParams),
2708 psdu->GetDuration());
2712 m_txTimer.GotResponseFrom(sender);
2714 if (m_txTimer.GetStasExpectedToRespond().empty())
2718 m_channelAccessManager->NotifyAckTimeoutResetNow();
2720 if (!m_multiStaBaEvent.IsPending())
2725 m_edca->ResetCw(m_linkId);
2726 TransmissionSucceeded();
2734 if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
2735 m_txTimer.GetReason() == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF)
2739 if (!m_txTimer.GetStasExpectedToRespond().contains(sender))
2741 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2744 if (std::none_of(psdu->begin(), psdu->end(), [](
Ptr<WifiMpdu> mpdu) {
2745 return mpdu->GetHeader().IsQosData() && !mpdu->GetHeader().HasData();
2748 NS_LOG_WARN(
"No QoS Null frame in the received PSDU");
2752 NS_LOG_DEBUG(
"Received QoS Null frames in a TB PPDU from " << sender);
2755 m_txTimer.GotResponseFrom(sender);
2757 if (m_txTimer.GetStasExpectedToRespond().empty())
2761 m_channelAccessManager->NotifyAckTimeoutResetNow();
2765 m_edca->ResetCw(m_linkId);
2766 TransmissionSucceeded();
2773 if (m_triggerFrameInAmpdu)
2776 auto psduIt = psdu->begin();
2777 while (psduIt != psdu->end())
2779 if ((*psduIt)->GetHeader().IsTrigger())
2781 ReceiveMpdu(*psduIt, rxSignalInfo, txVector,
false);
2786 m_triggerFrameInAmpdu =
false;
2791 VhtFrameExchangeManager::EndReceiveAmpdu(psdu, rxSignalInfo, txVector, perMpduStatus);
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
bool IsPending() const
This method is syntactic sugar for !IsExpired().
std::set< Mac48Address > m_sentRtsTo
the STA(s) which we sent an RTS to (waiting for CTS)
void DoCtsTimeout(Ptr< WifiPsdu > psdu)
Take required actions when the CTS timer fired after sending an RTS to protect the given PSDU expires...
uint8_t m_linkId
the ID of the link this object is associated with
Ptr< WifiMac > m_mac
the MAC layer on this station
virtual void SetWifiMac(const Ptr< WifiMac > mac)
Set the MAC layer to use.
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager() const
virtual void Reset()
Reset this frame exchange manager.
Mac48Address m_self
the MAC address of this device
virtual void StartProtection(const WifiTxParameters &txParams)
Start the protection mechanism indicated by the given TX parameters.
WifiTxTimer m_txTimer
the timer set upon frame transmission
std::set< Mac48Address > m_protectedStas
STAs that have replied to an RTS in this TXOP.
virtual Time GetRtsDurationId(const WifiTxVector &rtsTxVector, Time txDuration, Time response) const
Compute how to set the Duration/ID field of an RTS frame to send to protect a frame transmitted with ...
virtual void ProtectionCompleted()
Transmit prepared frame 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
MHz_u m_allowedWidth
the allowed width for the current transmission
virtual void RxStartIndication(WifiTxVector txVector, Time psduDuration)
virtual Time GetMuRtsDurationId(uint32_t muRtsSize, const WifiTxVector &muRtsTxVector, Time txDuration, Time response) const
Compute how to set the Duration/ID field of an MU-RTS Trigger Frame to send to protect a frame transm...
Ptr< ApWifiMac > m_apMac
MAC pointer (null if not an AP)
void DoDispose() override
Destructor implementation.
void Reset() override
Reset this frame exchange manager.
WifiMode GetCtsModeAfterMuRts() const
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.
void DoCtsAfterMuRtsTimeout(Ptr< WifiMpdu > muRts, const WifiTxVector &txVector, bool updateFailedCw)
Called when no CTS frame is received after an MU-RTS.
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.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
static Time Now()
Return the current simulation virtual time.
double Get() const
Return the SNR value.
Simulation virtual time values and global simulation resolution.
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
bool 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.
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,...
std::optional< Time > m_txDuration
TX duration of the frame.
std::unique_ptr< WifiProtection > m_protection
protection method
uint32_t GetSize(Mac48Address receiver) const
Get the size in bytes of the (A-)MPDU addressed to the given receiver.
std::unique_ptr< WifiAcknowledgment > m_acknowledgment
acknowledgment method
const PsduInfo * GetPsduInfo(Mac48Address receiver) const
Get a pointer to the information about the PSDU addressed to the given receiver, if present,...
void UndoAddMpdu()
Undo the addition of the last MPDU added by calling AddMpdu().
WifiTxVector m_txVector
TXVECTOR of the frame being prepared.
void AddMpdu(Ptr< const WifiMpdu > mpdu)
Record that an MPDU is being added to the current frame.
void Clear()
Reset the TX parameters.
bool IsRunning() const
Return true if the timer is running.
Reason
The reason why the timer was started.
@ WAIT_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.
uint8_t GetBssColor() const
Get the BSS color.
void SetGuardInterval(Time guardInterval)
Sets the guard interval duration (in nanoseconds)
void SetTriggerResponding(bool triggerResponding)
Set the Trigger Responding parameter to the given value.
WifiMode GetMode(uint16_t staId=SU_STA_ID) const
If this TX vector is associated with an SU PPDU, return the selected payload transmission mode.
void SetHeMuUserInfo(uint16_t staId, HeMuUserInfo userInfo)
Set the HE MU user-specific transmission information for the given STA-ID.
WifiPreamble GetPreambleType() const
void SetAggregation(bool aggregation)
Sets if PSDU contains A-MPDU.
void SetChannelWidth(MHz_u channelWidth)
Sets the selected channelWidth.
const HeMuUserInfoMap & GetHeMuUserInfoMap() const
Get a const reference to the map HE MU user-specific transmission information indexed by STA-ID.
WifiModulationClass GetModulationClass() const
Get the modulation class specified by this TXVECTOR.
void SetLength(uint16_t length)
Set the LENGTH field of the L-SIG.
MHz_u GetChannelWidth() const
void SetSigBMode(const WifiMode &mode)
Set the MCS used for SIG-B.
void SetBssColor(uint8_t color)
Set the BSS color.
void SetMode(WifiMode mode)
Sets the selected payload transmission mode.
void SetPreambleType(WifiPreamble preamble)
Sets the preamble type.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
#define NS_ABORT_IF(cond)
Abnormal program termination if a condition is true.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_WARN(msg)
Use NS_LOG to output a message of level LOG_WARN.
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Time Seconds(double value)
Construct a Time in the indicated unit.
AcIndex
This enumeration defines the Access Categories as an enumeration with values corresponding to the AC ...
@ WIFI_PHY_BAND_2_4GHZ
The 2.4 GHz band.
@ WIFI_MOD_CLASS_VHT
VHT (Clause 22)
Declaration of ns3::HePhy class and ns3::HeSigAParameters struct.
void(* Time)(Time oldValue, Time newValue)
TracedValue callback signature for Time.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
U * PeekPointer(const Ptr< U > &p)
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
bool IsTrigger(const WifiPsduMap &psduMap)
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
uint32_t GetBlockAckRequestSize(BlockAckReqType type)
Return the total BlockAckRequest size (including FCS trailer).
uint32_t GetMuBarSize(std::list< BlockAckReqType > types)
Return the total MU-BAR size (including FCS trailer).
const std::map< AcIndex, WifiAc > wifiAcList
Map containing the four ACs in increasing order of priority (according to Table 10-1 "UP-to-AC Mappin...
uint32_t GetBlockAckSize(BlockAckType type)
Return the total BlockAck size (including FCS trailer).
Ptr< T1 > StaticCast(const Ptr< T2 > &p)
Cast a Ptr.
bool IsDlMu(WifiPreamble preamble)
Return true if a preamble corresponds to a downlink multi-user transmission.
uint32_t GetAckSize()
Return the total Ack size (including FCS trailer).
static constexpr uint16_t SU_STA_ID
STA_ID to identify a single user (SU)
uint32_t GetCtsSize()
Return the total CTS size (including FCS trailer).
std::unordered_map< uint16_t, Ptr< WifiPsdu > > WifiPsduMap
Map of PSDUs indexed by STA-ID.
std::vector< uint8_t > m_bitmapLen
Length (bytes) of included bitmaps.
RxSignalInfo structure containing info on the received signal.
double snr
SNR in linear scale.
WifiAcknowledgment is an abstract base struct.
const Method method
acknowledgment method
std::optional< Time > acknowledgmentTime
time required by the acknowledgment method
WifiDlMuAggregateTf specifies that a DL MU PPDU made of PSDUs including each a MU-BAR Trigger Frame i...
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.