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);
124 phy->TraceConnectWithoutContext(
"PhyRxPayloadBegin",
149 "A Multi-User Scheduler can only be aggregated to an HE AP");
170 (!(mpdu = edca->PeekNextMpdu(
m_linkId)) ||
171 (mpdu->GetHeader().IsQosData() && !mpdu->GetHeader().GetAddr1().IsGroup() &&
173 mpdu->GetHeader().GetQosTid()))))
192 "The Multi-user Scheduler returned DL_MU_TX with empty psduMap, do not transmit");
203 auto packet = Create<Packet>();
225 if (!mpdu->GetHeader().IsTrigger())
263 <<
") incompatible with Basic Trigger Frame");
267 <<
") incompatible with BSRP Trigger Frame");
269 auto txVector = trigger.GetHeTbTxVector(trigger.begin()->GetAid12());
286 if (mpdu->IsQueued())
303 "Cannot use RTS/CTS with MU PPDUs");
329 for (
const auto& userInfo : protection->
muRts)
331 const auto addressIt = aidAddrMap.find(userInfo.GetAid12());
332 NS_ASSERT_MSG(addressIt != aidAddrMap.end(),
"AID not found");
357 NS_LOG_FUNCTION(
this << muRtsSize << muRtsTxVector << txDuration << response);
395 payload->AddHeader(protection->
muRts);
397 auto mpdu = Create<WifiMpdu>(payload, hdr);
400 mpdu->GetHeader().SetDuration(
450 if (mpdu->IsQueued())
458 const auto& hdr =
m_psduMap.cbegin()->second->GetHeader(0);
459 if (!hdr.GetAddr1().IsGroup())
464 if (!hdr.GetAddr1().IsGroup() &&
489 for (
const auto& [staId, psdu] :
m_psduMap)
500 auto it = std::find_if(
503 [&to](std::pair<uint16_t,
Ptr<WifiPsdu>> psdu) { return psdu.second->GetAddr1() == to; });
504 if (it != psduMap.end())
560 std::set<uint8_t> tids = psdu.second->GetTids();
562 "Acknowledgment method incompatible with a Multi-TID A-MPDU");
563 uint8_t tid = *tids.begin();
581 mpdu = *psdu->begin();
607 std::map<uint16_t, CtrlBAckRequestHeader> recipients;
618 staIt->second.blockAckTxVector.GetHeMuUserInfo(staId));
619 recipients.emplace(staId, staIt->second.barHeader);
692 auto psduMapIt = std::find_if(
m_psduMap.begin(),
695 return psdu.second->GetAddr1() == station.first;
700 std::vector<Ptr<WifiMpdu>> mpduList(psduMapIt->second->begin(),
701 psduMapIt->second->end());
702 NS_ASSERT(mpduList.size() == psduMapIt->second->GetNMpdus());
705 station.second.blockAckTxVector.SetLength(acknowledgment->
ulLength);
706 mpduList.push_back(
PrepareMuBar(station.second.blockAckTxVector,
707 {{psduMapIt->first, station.second.barHeader}}));
708 psduMapIt->second = Create<WifiPsdu>(std::move(mpduList));
711 station.second.blockAckTxVector.GetHeMuUserInfo(psduMapIt->first));
716 &acknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
726 mpdu = *m_psduMap.begin()->second->begin();
732 m_staExpectTbPpduFrom.clear();
736 m_staExpectTbPpduFrom.insert(station.first.first);
746 m_trigVector = GetTrigVector(m_muScheduler->GetUlMuInfo(m_linkId).trigger);
752 !m_txParams.m_txVector.IsUlMu() &&
IsTrigger(m_psduMap))
754 CtrlTriggerHeader& trigger = m_muScheduler->GetUlMuInfo(m_linkId).trigger;
759 m_staExpectTbPpduFrom.clear();
761 for (
const auto& userInfo : trigger)
763 auto staIt = m_apMac->GetStaList(m_linkId).find(userInfo.GetAid12());
764 NS_ASSERT(staIt != m_apMac->GetStaList(m_linkId).end());
765 m_staExpectTbPpduFrom.insert(staIt->second);
769 txVector = trigger.GetHeTbTxVector(trigger.begin()->GetAid12());
770 responseTxVector = &txVector;
771 m_trigVector = GetTrigVector(m_muScheduler->GetUlMuInfo(m_linkId).trigger);
776 else if (m_txParams.m_txVector.IsUlMu() &&
781 NS_ASSERT(m_staMac && m_staMac->IsAssociated());
782 txVector = GetWifiRemoteStationManager()->GetBlockAckTxVector(
783 m_psduMap.begin()->second->GetAddr1(),
784 m_txParams.m_txVector);
785 responseTxVector = &txVector;
790 else if (m_txParams.m_txVector.IsUlMu() &&
797 NS_ABORT_MSG(
"Unable to handle the selected acknowledgment method ("
798 << m_txParams.m_acknowledgment.get() <<
")");
803 for (
const auto& psdu : m_psduMap)
805 psduMap.emplace(psdu.first, psdu.second);
809 if (m_txParams.m_txVector.IsUlMu())
812 m_txParams.m_txVector,
813 m_phy->GetPhyBand());
818 m_phy->CalculateTxDuration(psduMap, m_txParams.m_txVector, m_phy->GetPhyBand());
821 Time durationId = GetPsduDurationId(txDuration, m_txParams);
822 for (
auto& psdu : m_psduMap)
824 psdu.second->SetDuration(durationId);
830 if (!m_txParams.m_txVector.IsUlMu())
837 Time timeout = txDuration + m_phy->GetSifs() + m_phy->GetSlot() +
838 m_phy->CalculatePhyPreambleAndHeaderDuration(*responseTxVector);
839 m_channelAccessManager->NotifyAckTimeoutStartNow(
timeout);
846 m_txTimer.Set(timerType,
851 m_txParams.m_txVector);
855 m_txTimer.Set(timerType,
860 m_txParams.m_txVector);
863 m_txTimer.Set(timerType,
868 &m_staExpectTbPpduFrom,
869 m_staExpectTbPpduFrom.size());
873 m_txTimer.Set(timerType,
878 &m_staExpectTbPpduFrom,
879 m_staExpectTbPpduFrom.size());
882 m_txTimer.Set(timerType,
886 m_psduMap.begin()->second,
887 m_txParams.m_txVector);
896 ForwardPsduMapDown(psduMap, m_txParams.m_txVector);
903 auto hePhy = StaticCast<HePhy>(m_phy->GetPhyEntity(responseTxVector->GetModulationClass()));
904 hePhy->SetTrigVector(m_trigVector, m_txTimer.GetDelayLeft());
921 auto sigBMode = hePhy->GetSigBMode(txVector);
925 for (
const auto& psdu : psduMap)
927 NS_LOG_DEBUG(
"Transmitting: [STAID=" << psdu.first <<
", " << *psdu.second <<
"]");
930 for (
const auto& [staId, psdu] : psduMap)
932 FinalizeMacHeader(psdu);
933 NotifyTxToEdca(psdu);
935 if (psduMap.size() > 1 || psduMap.begin()->second->IsAggregate() ||
936 psduMap.begin()->second->IsSingle())
941 m_phy->Send(psduMap, txVector);
945HeFrameExchangeManager::PrepareMuBar(
const WifiTxVector& responseTxVector,
946 std::map<uint16_t, CtrlBAckRequestHeader> recipients)
const
953 SetTargetRssi(muBar);
959 for (
auto& userInfo : muBar)
961 auto recipientIt = recipients.find(userInfo.GetAid12());
962 NS_ASSERT(recipientIt != recipients.end());
965 userInfo.SetMuBarTriggerDepUserInfo(recipientIt->second);
969 bar->AddHeader(muBar);
977 rxAddress = Mac48Address::GetBroadcast();
982 rxAddress = m_apMac->GetStaList(m_linkId).at(recipients.begin()->first);
994 return Create<WifiMpdu>(bar, hdr);
1003 if (protection->
method == WifiProtection::MU_RTS_CTS)
1011 GetCtsTxVectorAfterMuRts(muRtsCtsProtection->
muRts,
1012 muRtsCtsProtection->
muRts.
begin()->GetAid12());
1017 m_phy->CalculateTxDuration(muRtsSize,
1019 m_phy->GetPhyBand()) +
1020 m_phy->CalculateTxDuration(
GetCtsSize(), ctsTxVector, m_phy->GetPhyBand()) +
1021 2 * m_phy->GetSifs();
1025 VhtFrameExchangeManager::CalculateProtectionTime(protection);
1038 if (acknowledgment->
method == WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE)
1056 m_phy->CalculateTxDuration(
GetAckSize(), info.ackTxVector, m_phy->GetPhyBand());
1063 duration += m_phy->GetSifs() + m_phy->CalculateTxDuration(
GetBlockAckSize(info.baType),
1064 info.blockAckTxVector,
1065 m_phy->GetPhyBand());
1070 const auto& info = stations.second;
1071 duration += m_phy->GetSifs() +
1073 info.blockAckReqTxVector,
1074 m_phy->GetPhyBand()) +
1077 info.blockAckTxVector,
1078 m_phy->GetPhyBand());
1086 else if (acknowledgment->
method == WifiAcknowledgment::DL_MU_TF_MU_BAR)
1095 const auto& info = stations.second;
1096 NS_ASSERT(info.blockAckTxVector.GetHeMuUserInfoMap().size() == 1);
1097 uint16_t staId = info.blockAckTxVector.GetHeMuUserInfoMap().begin()->first;
1099 info.blockAckTxVector,
1100 m_phy->GetPhyBand(),
1103 if (currBlockAckDuration > duration)
1105 duration = currBlockAckDuration;
1112 ->second.blockAckTxVector;
1113 std::tie(dlMuTfMuBarAcknowledgment->
ulLength, duration) =
1114 HePhy::ConvertHeTbPpduDurationToLSigLength(duration, txVector, m_phy->GetPhyBand());
1120 muBarSize = MpduAggregator::GetSizeIfAggregated(muBarSize, 0);
1124 m_phy->CalculateTxDuration(muBarSize,
1126 m_phy->GetPhyBand()) +
1127 m_phy->GetSifs() + duration;
1132 else if (acknowledgment->
method == WifiAcknowledgment::DL_MU_AGGREGATE_TF)
1142 const auto& info = stations.second;
1143 NS_ASSERT(info.blockAckTxVector.GetHeMuUserInfoMap().size() == 1);
1144 uint16_t staId = info.blockAckTxVector.GetHeMuUserInfoMap().begin()->first;
1146 info.blockAckTxVector,
1147 m_phy->GetPhyBand(),
1150 if (currBlockAckDuration > duration)
1152 duration = currBlockAckDuration;
1160 std::tie(dlMuAggrTfAcknowledgment->
ulLength, duration) =
1161 HePhy::ConvertHeTbPpduDurationToLSigLength(duration, txVector, m_phy->GetPhyBand());
1167 else if (acknowledgment->
method == WifiAcknowledgment::UL_MU_MULTI_STA_BA)
1173 m_phy->GetPhyBand());
1179 else if (acknowledgment->
method == WifiAcknowledgment::ACK_AFTER_TB_PPDU)
1188 VhtFrameExchangeManager::CalculateAcknowledgmentTime(acknowledgment);
1193HeFrameExchangeManager::GetCtsModeAfterMuRts()
const
1198 : OfdmPhy::GetOfdmRate6Mbps();
1203 uint16_t staId)
const
1208 NS_ASSERT_MSG(userInfoIt != trigger.
end(),
"User Info field for AID=" << staId <<
" not found");
1211 if (uint8_t ru = userInfoIt->GetMuRtsRuAllocation(); ru < 65)
1229 auto txVector = GetWifiRemoteStationManager()->GetCtsTxVector(m_bssid, GetCtsModeAfterMuRts());
1231 txVector.SetChannelWidth(bw);
1237HeFrameExchangeManager::GetTxDuration(
uint32_t ppduPayloadSize,
1243 return VhtFrameExchangeManager::GetTxDuration(ppduPayloadSize, receiver, txParams);
1250 txParams.
m_acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF)
1260 MpduAggregator::GetSizeIfAggregated(info->second.muBarSize, ppduPayloadSize);
1263 uint16_t staId = (txParams.
m_txVector.
IsDlMu() ? m_apMac->GetAssociationId(receiver, m_linkId)
1264 : m_staMac->GetAssociationId());
1265 Time psduDuration = m_phy->CalculateTxDuration(ppduPayloadSize,
1267 m_phy->GetPhyBand(),
1275 const std::set<Mac48Address>* staMissedTbPpduFrom,
1276 std::size_t nSolicitedStations)
1278 NS_LOG_FUNCTION(
this << psduMap << staMissedTbPpduFrom->size() << nSolicitedStations);
1284 NS_ASSERT(!staMissedTbPpduFrom->empty());
1287 if (staMissedTbPpduFrom->size() == nSolicitedStations)
1290 m_edca->UpdateFailedCw(m_linkId);
1292 TransmissionFailed();
1294 else if (!m_multiStaBaEvent.IsRunning())
1296 m_edca->ResetCw(m_linkId);
1297 TransmissionSucceeded();
1304HeFrameExchangeManager::BlockAcksInTbPpduTimeout(
1306 const std::set<Mac48Address>* staMissedBlockAckFrom,
1307 std::size_t nSolicitedStations)
1312 NS_ASSERT(m_txParams.m_acknowledgment &&
1313 (m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF ||
1314 m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_TF_MU_BAR));
1317 NS_ASSERT(!staMissedBlockAckFrom->empty());
1321 if (staMissedBlockAckFrom->size() == nSolicitedStations)
1325 GetWifiRemoteStationManager()->ReportDataFailed(*psduMap->begin()->second->begin());
1337 DequeueMpdu(m_triggerFrame);
1338 m_triggerFrame =
nullptr;
1341 for (
const auto& sta : *staMissedBlockAckFrom)
1350 MissedBlockAck(psdu, m_txParams.m_txVector, psduResetCw);
1351 resetCw = resetCw || psduResetCw;
1358 m_edca->ResetCw(m_linkId);
1362 m_edca->UpdateFailedCw(m_linkId);
1365 if (staMissedBlockAckFrom->size() == nSolicitedStations)
1368 TransmissionFailed();
1372 TransmissionSucceeded();
1385 GetWifiRemoteStationManager()->ReportDataFailed(*psdu->begin());
1387 MissedBlockAck(psdu, m_txParams.m_txVector, resetCw);
1402 VhtFrameExchangeManager::NormalAckTimeout(mpdu, txVector);
1407 for (
auto& psdu : m_psduMap)
1411 if (mpdu->IsQueued())
1413 m_mac->GetTxopQueue(mpdu->GetQueueAc())->GetOriginal(mpdu)->GetHeader().SetRetry();
1414 mpdu->ResetInFlight(m_linkId);
1426 VhtFrameExchangeManager::BlockAckTimeout(psdu, txVector);
1431 for (
auto& psdu : m_psduMap)
1435 if (mpdu->IsQueued())
1437 mpdu->GetHeader().SetRetry();
1453 for (
const auto& userInfoField : trigger)
1456 userInfoField.GetAid12(),
1457 {userInfoField.GetRuAllocation(), userInfoField.GetUlMcs(), userInfoField.GetNss()});
1469 uint16_t staId = m_staMac->GetAssociationId();
1476 NS_ASSERT_MSG(heConfiguration,
"This STA has to be an HE station to send an HE TB PPDU");
1479 if (userInfoIt->IsUlTargetRssiMaxTxPower())
1481 NS_LOG_LOGIC(
"AP requested using the max transmit power (" << m_phy->GetTxPowerEnd()
1487 uint8_t powerLevel = GetWifiRemoteStationManager()->GetDefaultTxPowerLevel();
1505 auto optRssi = GetMostRecentRssi(triggerSender);
1511 double reqTxPowerDbm =
static_cast<double>(userInfoIt->GetUlTargetRssi() + pathLossDb);
1514 uint8_t numPowerLevels = m_phy->GetNTxPower();
1515 if (numPowerLevels > 1)
1517 double stepDbm = (m_phy->GetTxPowerEnd() - m_phy->GetTxPowerStart()) / (numPowerLevels - 1);
1518 powerLevel =
static_cast<uint8_t
>(
1519 ceil((reqTxPowerDbm - m_phy->GetTxPowerStart()) /
1521 if (powerLevel > numPowerLevels)
1523 powerLevel = numPowerLevels;
1526 if (reqTxPowerDbm > m_phy->GetPowerDbm(powerLevel))
1529 << reqTxPowerDbm <<
"dBm) cannot be satisfied (max: " << m_phy->GetTxPowerEnd()
1534 <<
"input {pathLoss=" << pathLossDb <<
"dB, reqTxPower=" << reqTxPowerDbm <<
"dBm}"
1535 <<
" output {powerLevel=" << +powerLevel <<
" -> "
1536 << m_phy->GetPowerDbm(powerLevel) <<
"dBm}"
1537 <<
" PHY power capa {min=" << m_phy->GetTxPowerStart() <<
"dBm, max="
1538 << m_phy->GetTxPowerEnd() <<
"dBm, levels:" << +numPowerLevels <<
"}");
1543std::optional<double>
1544HeFrameExchangeManager::GetMostRecentRssi(
const Mac48Address& address)
const
1546 return GetWifiRemoteStationManager()->GetMostRecentRssi(address);
1556 m_phy->GetPowerDbm(GetWifiRemoteStationManager()->GetDefaultTxPowerLevel())));
1557 for (
auto& userInfo : trigger)
1559 const auto staList = m_apMac->GetStaList(m_linkId);
1560 auto itAidAddr = staList.find(userInfo.GetAid12());
1562 auto optRssi = GetMostRecentRssi(itAidAddr->second);
1565 rssi = (rssi >= -20)
1567 : ((rssi <= -110) ? -110 : rssi);
1568 userInfo.SetUlTargetRssi(rssi);
1577 auto txVectorCopy = txVector;
1579 if (psdu->GetNMpdus() == 1 && psdu->GetHeader(0).IsTrigger())
1582 psdu->GetPayload(0)->PeekHeader(trigger);
1596 if (m_staMac !=
nullptr && m_staMac->IsAssociated() &&
1607 psdu = Create<const WifiPsdu>(Create<Packet>(), rts);
1611 GetWifiRemoteStationManager()->GetCtsTxVector(m_bssid, GetCtsModeAfterMuRts());
1614 VhtFrameExchangeManager::PostProcessFrame(psdu, txVectorCopy);
1624 if (!UlMuCsMediumIdle(trigger))
1626 NS_LOG_DEBUG(
"UL MU CS indicated medium busy, cannot send CTS");
1630 NS_ASSERT(m_staMac !=
nullptr && m_staMac->IsAssociated());
1631 WifiTxVector ctsTxVector = GetCtsTxVectorAfterMuRts(trigger, m_staMac->GetAssociationId());
1634 DoSendCtsAfterRts(muRtsHdr, ctsTxVector, muRtsSnr);
1644 txParams.
m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
1657 receiver = staInfo.first.first;
1658 uint8_t tid = staInfo.first.second;
1659 std::size_t index = staInfo.second;
1661 blockAck.
SetAid11(m_apMac->GetAssociationId(receiver, m_linkId), index);
1667 NS_LOG_DEBUG(
"Multi-STA Block Ack: Sending All-ack to=" << receiver);
1675 NS_LOG_DEBUG(
"Multi-STA Block Ack: Sending Ack to=" << receiver);
1683 auto agreement = m_mac->GetBaAgreementEstablishedAsRecipient(receiver, tid);
1685 agreement->get().FillBlockAckBitmap(&blockAck, index);
1686 NS_LOG_DEBUG(
"Multi-STA Block Ack: Sending Block Ack with seq="
1688 <<
" tid=" << +tid);
1696 : Mac48Address::GetBroadcast());
1702 packet->AddHeader(blockAck);
1708 m_phy->GetPhyBand());
1720 if (m_edca->GetTxopLimit(m_linkId).IsZero())
1723 psdu->SetDuration(
Max(durationId - m_phy->GetSifs() - txDuration,
Seconds(0)));
1728 psdu->SetDuration(
Max(m_edca->GetRemainingTxop(m_linkId) - txDuration,
Seconds(0)));
1731 psdu->GetPayload(0)->AddPacketTag(m_muSnrTag);
1737 m_edca->ResetCw(m_linkId);
1739 Simulator::Schedule(txDuration, &HeFrameExchangeManager::TransmissionSucceeded,
this);
1748 NS_ASSERT(m_staMac && m_staMac->IsAssociated());
1750 NS_LOG_DEBUG(
"Received a Trigger Frame (basic variant) soliciting a transmission");
1752 if (!UlMuCsMediumIdle(trigger))
1763 std::vector<uint8_t> tids;
1764 uint16_t staId = m_staMac->GetAssociationId();
1767 for (uint8_t i = 0; i < 4; i++)
1770 tids.push_back(acIt->second.GetHighTid());
1771 tids.push_back(acIt->second.GetLowTid());
1783 Time ppduDuration = HePhy::ConvertLSigLengthToHeTbPpduDuration(trigger.
GetUlLength(),
1785 m_phy->GetPhyBand());
1787 for (
const auto& tid : tids)
1791 if (!m_mac->GetBaAgreementEstablishedAsOriginator(hdr.
GetAddr2(), tid))
1801 if (
auto mpdu = GetBar(edca->GetAccessCategory(), tid, hdr.
GetAddr2());
1802 mpdu && TryAddMpdu(mpdu, txParams, ppduDuration))
1805 psdu = Create<WifiPsdu>(mpdu,
true);
1811 GetWifiRemoteStationManager()->GetMldAddress(hdr.
GetAddr2()).value_or(hdr.
GetAddr2());
1812 if (
auto mpdu = edca->PeekNextMpdu(m_linkId, tid, receiver))
1814 mpdu = CreateAliasIfNeeded(mpdu);
1815 if (
auto item = edca->GetNextMpdu(m_linkId, mpdu, txParams, ppduDuration,
false))
1818 std::vector<Ptr<WifiMpdu>> mpduList =
1819 m_mpduAggregator->GetNextAmpdu(item, txParams, ppduDuration);
1820 psdu = (mpduList.size() > 1 ? Create<WifiPsdu>(std::move(mpduList))
1821 : Create<WifiPsdu>(item,
true));
1829 psdu->SetDuration(hdr.
GetDuration() - m_phy->GetSifs() - ppduDuration);
1830 SendPsduMapWithProtection(
WifiPsduMap{{staId, psdu}}, txParams);
1835 SendQosNullFramesInTbPpdu(trigger, hdr);
1845 NS_ASSERT(m_staMac && m_staMac->IsAssociated());
1849 if (!UlMuCsMediumIdle(trigger))
1872 Time ppduDuration = HePhy::ConvertLSigLengthToHeTbPpduDuration(trigger.
GetUlLength(),
1874 m_phy->GetPhyBand());
1878 std::vector<Ptr<WifiMpdu>> mpduList;
1883 IsWithinSizeAndTimeLimits(
1884 txParams.
GetSizeIfAddMpdu(mpdu = Create<WifiMpdu>(Create<Packet>(), header)),
1889 if (!m_mac->GetBaAgreementEstablishedAsOriginator(hdr.
GetAddr2(), tid))
1891 NS_LOG_DEBUG(
"Skipping tid=" << +tid <<
" because no agreement established");
1896 NS_LOG_DEBUG(
"Aggregating a QoS Null frame with tid=" << +tid);
1904 UpdateTxDuration(mpdu->GetHeader().GetAddr1(), txParams);
1905 mpduList.push_back(mpdu);
1909 if (mpduList.empty())
1911 NS_LOG_DEBUG(
"Not enough time to send a QoS Null frame");
1915 Ptr<WifiPsdu> psdu = (mpduList.size() > 1 ? Create<WifiPsdu>(std::move(mpduList))
1916 : Create<WifiPsdu>(mpduList.front(),
true));
1917 uint16_t staId = m_staMac->GetAssociationId();
1918 SendPsduMapWithProtection(
WifiPsduMap{{staId, psdu}}, txParams);
1929 auto agreement = m_mac->GetBaAgreementEstablishedAsRecipient(m_bssid, tid);
1933 NS_LOG_DEBUG(
"There's not a valid agreement for this BlockAckReq");
1937 if (!UlMuCsMediumIdle(trigger))
1943 auto txVector = GetHeTbTxVector(trigger, m_bssid);
1944 SendBlockAck(*agreement, durationId, txVector, snr);
1958 const auto ra = psdu->GetAddr1();
1959 const auto ta = psdu->GetAddr2();
1960 const auto bssid = psdu->GetHeader(0).GetAddr3();
1963 if (ra == m_bssid || ta == m_bssid || bssid == m_bssid)
1971 if (psdu->GetHeader(0).IsCtl() && ta == empty && ra == m_txopHolder)
1985 if (bssid != empty && bssid != m_bssid)
1993 if (bssid == empty && ta != empty && ra != empty && ta != m_bssid && ra != m_bssid)
2006 const auto bssColor = m_mac->GetHeConfiguration()->GetBssColor();
2009 return bssColor != 0 && bssColor == txVector.
GetBssColor();
2017 if (!psdu->HasNav())
2022 if (psdu->GetAddr1() == m_self)
2032 if (!IsIntraBssPpdu(psdu, txVector))
2034 NS_LOG_DEBUG(
"PPDU not classified as intra-BSS, update the basic NAV");
2035 VhtFrameExchangeManager::UpdateNav(psdu, txVector);
2039 NS_LOG_DEBUG(
"PPDU classified as intra-BSS, update the intra-BSS NAV");
2040 Time duration = psdu->GetDuration();
2043 if (psdu->GetHeader(0).IsCfEnd())
2049 NS_LOG_DEBUG(
"Received CF-End, resetting the intra-BSS NAV");
2050 IntraBssNavResetTimeout();
2056 auto intraBssNavEnd = Simulator::Now() + duration;
2057 if (intraBssNavEnd > m_intraBssNavEnd)
2059 m_intraBssNavEnd = intraBssNavEnd;
2060 NS_LOG_DEBUG(
"Updated intra-BSS NAV=" << m_intraBssNavEnd);
2071 if (psdu->GetHeader(0).IsRts())
2074 GetWifiRemoteStationManager()->GetCtsTxVector(psdu->GetAddr2(), txVector.
GetMode());
2075 auto navResetDelay =
2076 2 * m_phy->GetSifs() +
2077 WifiPhy::CalculateTxDuration(
GetCtsSize(), ctsTxVector, m_phy->GetPhyBand()) +
2078 m_phy->CalculatePhyPreambleAndHeaderDuration(ctsTxVector) + 2 * m_phy->GetSlot();
2079 m_intraBssNavResetEvent =
2080 Simulator::Schedule(navResetDelay,
2081 &HeFrameExchangeManager::IntraBssNavResetTimeout,
2085 NS_LOG_DEBUG(
"Current intra-BSS NAV=" << m_intraBssNavEnd);
2087 m_channelAccessManager->NotifyNavStartNow(duration);
2091HeFrameExchangeManager::ClearTxopHolderIfNeeded()
2094 if (m_intraBssNavEnd <= Simulator::Now())
2096 m_txopHolder.reset();
2101HeFrameExchangeManager::NavResetTimeout()
2104 m_navEnd = Simulator::Now();
2107 Time intraBssNav = Simulator::GetDelayLeft(m_intraBssNavResetEvent);
2108 m_channelAccessManager->NotifyNavResetNow(intraBssNav);
2112HeFrameExchangeManager::IntraBssNavResetTimeout()
2115 m_intraBssNavEnd = Simulator::Now();
2116 ClearTxopHolderIfNeeded();
2118 Time basicNav = Simulator::GetDelayLeft(m_navResetEvent);
2119 m_channelAccessManager->NotifyNavResetNow(basicNav);
2127 if (psdu->GetHeader(0).IsTrigger() && psdu->GetAddr2() == m_bssid)
2129 m_txopHolder = m_bssid;
2131 else if (!txVector.
IsUlMu())
2133 VhtFrameExchangeManager::SetTxopHolder(psdu, txVector);
2138HeFrameExchangeManager::VirtualCsMediumIdle()
const
2143 return m_navEnd <= Simulator::Now() && m_intraBssNavEnd <= Simulator::Now();
2159 const Time now = Simulator::Now();
2166 NS_ASSERT_MSG(m_staMac,
"UL MU CS is only performed by non-AP STAs");
2169 "No User Info field for STA (" << m_self
2170 <<
") AID=" << m_staMac->GetAssociationId());
2172 std::set<uint8_t> indices;
2176 auto ctsTxVector = GetCtsTxVectorAfterMuRts(trigger, m_staMac->GetAssociationId());
2177 auto bw = ctsTxVector.GetChannelWidth();
2178 indices = m_phy->GetOperatingChannel().GetAll20MHzChannelIndicesInPrimary(bw);
2183 m_phy->GetOperatingChannel().Get20MHzIndicesCoveringRu(userInfoIt->GetRuAllocation(),
2186 return !m_channelAccessManager->GetPer20MHzBusy(indices);
2196 NS_ASSERT(mpdu->GetHeader().GetAddr1().IsGroup() || mpdu->GetHeader().GetAddr1() == m_self);
2200 if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
2201 m_txTimer.GetReason() == WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF)
2204 NS_ASSERT(m_txParams.m_acknowledgment &&
2205 m_txParams.m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
2210 if (m_staExpectTbPpduFrom.find(sender) == m_staExpectTbPpduFrom.end())
2212 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2218 NS_LOG_DEBUG(
"Received a BlockAckReq in a TB PPDU from " << sender);
2221 mpdu->GetPacket()->PeekHeader(blockAckReq);
2224 GetBaManager(tid)->NotifyGotBlockAckRequest(
2225 m_mac->GetMldAddress(sender).value_or(sender),
2232 m_mac->GetBaTypeAsRecipient(sender, tid).m_bitmapLen.at(0));
2234 m_muSnrTag.Set(staId, rxSignalInfo.
snr);
2238 NS_LOG_DEBUG(
"Received an S-MPDU in a TB PPDU from " << sender <<
" (" << *mpdu <<
")");
2241 GetBaManager(tid)->NotifyGotMpdu(mpdu);
2247 m_muSnrTag.Set(staId, rxSignalInfo.
snr);
2256 VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
2263 m_multiStaBaEvent = Simulator::Schedule(m_phy->GetSifs(),
2264 &HeFrameExchangeManager::SendMultiStaBlockAck,
2266 std::cref(m_txParams),
2267 mpdu->GetHeader().GetDuration());
2271 m_staExpectTbPpduFrom.erase(sender);
2273 if (m_staExpectTbPpduFrom.empty())
2277 m_channelAccessManager->NotifyAckTimeoutResetNow();
2279 if (!m_multiStaBaEvent.IsRunning())
2284 m_edca->ResetCw(m_linkId);
2285 TransmissionSucceeded();
2293 if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
2294 m_txTimer.GetReason() == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF &&
2297 const auto& sender = hdr.
GetAddr2();
2299 if (m_staExpectTbPpduFrom.find(sender) == m_staExpectTbPpduFrom.end())
2301 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2306 NS_LOG_WARN(
"No QoS Null frame in the received MPDU");
2310 NS_LOG_DEBUG(
"Received a QoS Null frame in a TB PPDU from " << sender);
2313 m_staExpectTbPpduFrom.erase(sender);
2315 if (m_staExpectTbPpduFrom.empty())
2319 m_channelAccessManager->NotifyAckTimeoutResetNow();
2323 m_edca->ResetCw(m_linkId);
2324 TransmissionSucceeded();
2333 if (hdr.
IsCts() && m_txTimer.IsRunning() &&
2334 m_txTimer.GetReason() == WifiTxTimer::WAIT_CTS && m_psduMap.size() == 1)
2339 Mac48Address sender = m_psduMap.begin()->second->GetAddr1();
2343 mpdu->GetPacket()->PeekPacketTag(tag);
2344 GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
2345 GetWifiRemoteStationManager()->ReportRtsOk(m_psduMap.begin()->second->GetHeader(0),
2351 m_channelAccessManager->NotifyCtsTimeoutResetNow();
2352 Simulator::Schedule(m_phy->GetSifs(),
2353 &HeFrameExchangeManager::ProtectionCompleted,
2356 else if (hdr.
IsCts() && m_txTimer.IsRunning() &&
2357 m_txTimer.GetReason() == WifiTxTimer::WAIT_CTS_AFTER_MU_RTS)
2362 NS_LOG_DEBUG(
"Received a CTS frame in response to an MU-RTS");
2365 m_channelAccessManager->NotifyCtsTimeoutResetNow();
2366 Simulator::Schedule(m_phy->GetSifs(),
2367 &HeFrameExchangeManager::ProtectionCompleted,
2370 else if (hdr.
IsAck() && m_txTimer.IsRunning() &&
2371 m_txTimer.GetReason() == WifiTxTimer::WAIT_NORMAL_ACK_AFTER_DL_MU_PPDU)
2375 NS_ASSERT(m_txParams.m_acknowledgment->method ==
2376 WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE);
2382 uint16_t staId = m_apMac->GetAssociationId(
2385 auto it = m_psduMap.find(staId);
2390 mpdu->GetPacket()->PeekPacketTag(tag);
2391 ReceivedNormalAck(*it->second->begin(),
2392 m_txParams.m_txVector,
2405 m_txTimer.GetReason() == WifiTxTimer::WAIT_BLOCK_ACKS_IN_TB_PPDU)
2408 NS_LOG_DEBUG(
"Received BlockAck in TB PPDU from=" << sender);
2411 mpdu->GetPacket()->PeekPacketTag(tag);
2415 mpdu->GetPacket()->PeekHeader(blockAck);
2417 std::pair<uint16_t, uint16_t> ret =
2418 GetBaManager(tid)->NotifyGotBlockAck(m_linkId,
2420 m_mac->GetMldAddress(sender).value_or(sender),
2422 GetWifiRemoteStationManager()->ReportAmpduTxStatus(sender,
2427 m_txParams.m_txVector);
2430 if (m_staExpectTbPpduFrom.erase(sender) == 0)
2432 NS_LOG_WARN(
"Received a BlockAck from an unexpected stations: " << sender);
2436 if (m_staExpectTbPpduFrom.empty())
2440 m_channelAccessManager->NotifyAckTimeoutResetNow();
2444 DequeueMpdu(m_triggerFrame);
2445 m_triggerFrame =
nullptr;
2448 m_edca->ResetCw(m_linkId);
2450 TransmissionSucceeded();
2453 else if (hdr.
IsBlockAck() && m_txTimer.IsRunning() &&
2454 m_txTimer.GetReason() == WifiTxTimer::WAIT_BLOCK_ACK_AFTER_TB_PPDU)
2457 mpdu->GetPacket()->PeekHeader(blockAck);
2460 "A Multi-STA BlockAck is expected after a TB PPDU");
2463 NS_ASSERT(m_staMac && m_staMac->IsAssociated());
2466 NS_LOG_DEBUG(
"The sender is not the AP we are associated with");
2470 uint16_t staId = m_staMac->GetAssociationId();
2473 if (indices.empty())
2475 NS_LOG_DEBUG(
"No Per AID TID Info subfield intended for me");
2480 mpdu->GetPacket()->PeekPacketTag(tag);
2483 for (
const auto& index : indices)
2490 NS_ABORT_IF(m_psduMap.empty() || m_psduMap.begin()->first != staId);
2491 GetBaManager(tid)->NotifyGotAck(m_linkId, *m_psduMap.at(staId)->begin());
2500 NS_ABORT_IF(m_psduMap.empty() || m_psduMap.begin()->first != staId);
2501 std::set<uint8_t> tids = m_psduMap.at(staId)->GetTids();
2502 NS_ABORT_MSG_IF(tids.size() > 1,
"Multi-TID A-MPDUs not supported yet");
2503 tid = *tids.begin();
2506 std::pair<uint16_t, uint16_t> ret = GetBaManager(tid)->NotifyGotBlockAck(
2512 GetWifiRemoteStationManager()->ReportAmpduTxStatus(hdr.
GetAddr2(),
2517 m_txParams.m_txVector);
2520 if (m_psduMap.at(staId)->GetHeader(0).IsQosData() &&
2522 || std::any_of(blockAck.
GetBitmap(index).begin(),
2524 [](uint8_t b) { return b != 0; })))
2526 NS_ASSERT(m_psduMap.at(staId)->GetHeader(0).HasData());
2527 NS_ASSERT(m_psduMap.at(staId)->GetHeader(0).GetQosTid() == tid);
2532 m_mac->GetQosTxop(tid)->StartMuEdcaTimerNow(m_linkId);
2538 m_channelAccessManager->NotifyAckTimeoutResetNow();
2540 for (
const auto& [staId, psdu] : m_psduMap)
2542 if (psdu->GetNMpdus() == 1 && psdu->GetHeader(0).IsBlockAckReq())
2549 else if (hdr.
IsBlockAck() && m_txTimer.IsRunning() &&
2550 m_txTimer.GetReason() == WifiTxTimer::WAIT_BLOCK_ACK)
2556 VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
2569 m_triggerFrameInAmpdu =
true;
2574 mpdu->GetPacket()->PeekHeader(trigger);
2585 uint16_t staId = m_staMac->GetAssociationId();
2590 NS_LOG_DEBUG(
"Received MU-RTS Trigger Frame from=" << sender);
2591 GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
2601 Simulator::Schedule(m_phy->GetSifs(),
2602 &HeFrameExchangeManager::SendCtsAfterMuRts,
2611 NS_LOG_DEBUG(
"Received MU-BAR Trigger Frame from=" << sender);
2612 GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
2620 GetBaManager(tid)->NotifyGotBlockAckRequest(
2621 m_mac->GetMldAddress(sender).value_or(sender),
2625 Simulator::Schedule(m_phy->GetSifs(),
2626 &HeFrameExchangeManager::ReceiveMuBarTrigger,
2635 Simulator::Schedule(m_phy->GetSifs(),
2636 &HeFrameExchangeManager::ReceiveBasicTrigger,
2641 else if (trigger.
IsBsrp())
2643 Simulator::Schedule(m_phy->GetSifs(),
2644 &HeFrameExchangeManager::SendQosNullFramesInTbPpdu,
2653 VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
2661 VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
2669 const std::vector<bool>& perMpduStatus)
2671 std::set<uint8_t> tids = psdu->GetTids();
2673 if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
2674 m_txTimer.GetReason() == WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF)
2677 NS_ASSERT(m_txParams.m_acknowledgment &&
2678 m_txParams.m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
2683 if (m_staExpectTbPpduFrom.find(sender) == m_staExpectTbPpduFrom.end())
2685 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2689 NS_LOG_DEBUG(
"Received an A-MPDU in a TB PPDU from " << sender <<
" (" << *psdu <<
")");
2691 if (std::any_of(tids.begin(), tids.end(), [&psdu](uint8_t tid) {
2692 return psdu->GetAckPolicyForTid(tid) == WifiMacHeader::NORMAL_ACK;
2695 if (std::all_of(perMpduStatus.cbegin(), perMpduStatus.cend(), [](
bool v) { return v; }))
2706 for (
const auto& tid : tids)
2711 m_mac->GetBaTypeAsRecipient(sender, tid).m_bitmapLen.at(0));
2715 m_muSnrTag.Set(staId, rxSignalInfo.
snr);
2721 m_multiStaBaEvent = Simulator::Schedule(m_phy->GetSifs(),
2722 &HeFrameExchangeManager::SendMultiStaBlockAck,
2724 std::cref(m_txParams),
2725 psdu->GetDuration());
2729 m_staExpectTbPpduFrom.erase(sender);
2731 if (m_staExpectTbPpduFrom.empty())
2735 m_channelAccessManager->NotifyAckTimeoutResetNow();
2737 if (!m_multiStaBaEvent.IsRunning())
2742 m_edca->ResetCw(m_linkId);
2743 TransmissionSucceeded();
2751 if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
2752 m_txTimer.GetReason() == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF)
2756 if (m_staExpectTbPpduFrom.find(sender) == m_staExpectTbPpduFrom.end())
2758 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2761 if (std::none_of(psdu->begin(), psdu->end(), [](
Ptr<WifiMpdu> mpdu) {
2762 return mpdu->GetHeader().IsQosData() && !mpdu->GetHeader().HasData();
2765 NS_LOG_WARN(
"No QoS Null frame in the received PSDU");
2769 NS_LOG_DEBUG(
"Received QoS Null frames in a TB PPDU from " << sender);
2772 m_staExpectTbPpduFrom.erase(sender);
2774 if (m_staExpectTbPpduFrom.empty())
2778 m_channelAccessManager->NotifyAckTimeoutResetNow();
2782 m_edca->ResetCw(m_linkId);
2783 TransmissionSucceeded();
2790 if (m_triggerFrameInAmpdu)
2793 auto psduIt = psdu->begin();
2794 while (psduIt != psdu->end())
2796 if ((*psduIt)->GetHeader().IsTrigger())
2798 ReceiveMpdu(*psduIt, rxSignalInfo, txVector,
false);
2803 m_triggerFrameInAmpdu =
false;
2808 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
virtual void SetWifiPhy(const Ptr< WifiPhy > phy)
Set the PHY layer to use.
Ptr< ChannelAccessManager > m_channelAccessManager
the channel access manager
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 SetWifiPhy(const Ptr< WifiPhy > phy) override
Set the PHY layer to use.
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.
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.
virtual void TbPpduTimeout(WifiPsduMap *psduMap, const std::set< Mac48Address > *staMissedTbPpduFrom, std::size_t nSolicitedStations)
Take the necessary actions after that some TB PPDUs are missing in response to Trigger Frame.
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.
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...
std::set< Mac48Address > m_staExpectTbPpduFrom
set of stations expected to send a TB PPDU
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...
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
bool SendMpduFromBaManager(Ptr< WifiMpdu > mpdu, Time availableTime, bool initialFrame) override
If the given MPDU contains a BlockAckReq frame (the duration of which plus the response fits within t...
virtual void BlockAcksInTbPpduTimeout(WifiPsduMap *psduMap, const std::set< Mac48Address > *staMissedBlockAckFrom, std::size_t nSolicitedStations)
Take the necessary actions after that some BlockAck frames are missing in response to a DL MU PPDU.
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
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.
virtual bool SendMpduFromBaManager(Ptr< WifiMpdu > mpdu, Time availableTime, bool initialFrame)
If the given MPDU contains a BlockAckReq frame (the duration of which plus the response fits within t...
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.
void Set(Reason reason, const Time &delay, MEM mem_ptr, OBJ obj, Args... args)
This method is called when a frame soliciting a response is transmitted.
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
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.
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...
uint16_t ulLength
the UL Length field of the MU-BAR Trigger Frames
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...
std::map< Mac48Address, BlockAckReqInfo > stationsSendBlockAckReqTo
Set of stations receiving a BlockAckReq frame and replying with a BlockAck frame.
std::map< Mac48Address, BlockAckInfo > stationsReplyingWithBlockAck
Set of stations replying with a BlockAck frame (no more than one)
std::map< Mac48Address, AckInfo > stationsReplyingWithNormalAck
Set of stations replying with an Ack frame (no more than one)
WifiDlMuTfMuBar specifies that a DL MU PPDU is followed after a SIFS duration by a MU-BAR Trigger Fra...
std::list< BlockAckReqType > barTypes
BAR types.
std::map< Mac48Address, BlockAckInfo > stationsReplyingWithBlockAck
Set of stations replying with a BlockAck frame.
uint16_t ulLength
the UL Length field of the MU-BAR Trigger Frame
WifiTxVector muBarTxVector
TXVECTOR used to transmit the MU-BAR Trigger Frame.
WifiMuRtsCtsProtection specifies that MU-RTS/CTS protection method is used.
CtrlTriggerHeader muRts
MU-RTS.
WifiTxVector muRtsTxVector
MU-RTS TXVECTOR.
WifiNoAck specifies that no acknowledgment is required.
WifiNoProtection specifies that no protection method is used.
WifiProtection is an abstract base struct.
Time protectionTime
time required by the protection method
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.
WifiTxVector tbPpduTxVector
TXVECTOR for a TB PPDU.
WifiTxVector multiStaBaTxVector
TXVECTOR for the Multi-STA BlockAck.
std::map< std::pair< Mac48Address, uint8_t >, std::size_t > stationsReceivingMultiStaBa
Map (originator, tid) pairs to the their index in baType.