16#include "ns3/ap-wifi-mac.h"
17#include "ns3/erp-ofdm-phy.h"
19#include "ns3/recipient-block-ack-agreement.h"
20#include "ns3/snr-tag.h"
21#include "ns3/sta-wifi-mac.h"
22#include "ns3/wifi-mac-queue.h"
23#include "ns3/wifi-mac-trailer.h"
28#undef NS_LOG_APPEND_CONTEXT
29#define NS_LOG_APPEND_CONTEXT WIFI_FEM_NS_LOG_APPEND_CONTEXT
41 return psduMap.size() == 1 && psduMap.cbegin()->first ==
SU_STA_ID &&
42 psduMap.cbegin()->second->GetNMpdus() == 1 &&
43 psduMap.cbegin()->second->GetHeader(0).IsTrigger();
49 return psduMap.size() == 1 && psduMap.cbegin()->first ==
SU_STA_ID &&
50 psduMap.cbegin()->second->GetNMpdus() == 1 &&
51 psduMap.cbegin()->second->GetHeader(0).IsTrigger();
58 TypeId(
"ns3::HeFrameExchangeManager")
60 .AddConstructor<HeFrameExchangeManager>()
62 .AddAttribute(
"ContinueTxopAfterBsrp",
63 "Whether to continue a TXOP a SIFS after the reception of responses "
64 "to a BSRP Trigger Frame when TXOP limit is zero.",
122 "A Multi-User Scheduler can only be aggregated to an HE AP");
143 (!(mpdu = edca->PeekNextMpdu(
m_linkId)) ||
144 (mpdu->GetHeader().IsQosData() && !mpdu->GetHeader().GetAddr1().IsGroup() &&
145 m_mac->GetBaAgreementEstablishedAsOriginator(mpdu->GetHeader().GetAddr1(),
146 mpdu->GetHeader().GetQosTid()))))
165 "The Multi-user Scheduler returned DL_MU_TX with empty psduMap, do not transmit");
202 if (!
m_txParams.m_acknowledgment->acknowledgmentTime.has_value())
215 "Acknowledgment (" <<
m_txParams.m_acknowledgment.get()
216 <<
") incompatible with Basic Trigger Frame");
219 "Acknowledgment (" <<
m_txParams.m_acknowledgment.get()
220 <<
") incompatible with BSRP Trigger Frame");
222 auto txVector = trigger.GetHeTbTxVector(trigger.begin()->GetAid12());
223 *
m_txParams.m_acknowledgment->acknowledgmentTime +=
226 m_phy->GetPhyBand());
239 if (mpdu->IsQueued())
256 "Cannot use RTS/CTS with MU PPDUs");
273std::set<Mac48Address>
276 std::set<Mac48Address> recipients;
280 for (
const auto& userInfo : trigger)
282 const auto addressIt = aidAddrMap.find(userInfo.GetAid12());
283 NS_ASSERT_MSG(addressIt != aidAddrMap.end(),
"AID not found");
284 recipients.insert(addressIt->second);
304 NS_LOG_INFO(
"Multi-user scheduler aborted the transmission");
335 NS_LOG_FUNCTION(
this << muRtsSize << muRtsTxVector << txDuration << response);
339 const auto singleDurationId =
344 return singleDurationId;
381 protection->muRts.SetCsRequired(
true);
383 payload->AddHeader(protection->muRts);
389 mpdu->GetHeader().SetDuration(
391 protection->muRtsTxVector,
404 protection->muRtsTxVector,
405 m_phy->GetPhyBand()) +
416 protection->muRtsTxVector);
442 auto it = std::find_if(
445 [&to](std::pair<uint16_t,
Ptr<WifiPsdu>> psdu) { return psdu.second->GetAddr1() == to; });
446 if (it != psduMap.end())
479 for (
const auto& address :
m_txTimer.GetStasExpectedToRespond())
481 NS_LOG_DEBUG(address <<
" did not respond, hence it is no longer protected");
491 NS_LOG_DEBUG(
"Schedule another transmission in a SIFS after successful BSRP TF");
494 if (!StartTransmission(m_edca, Seconds(0)))
524 std::set<Mac48Address> staExpectResponseFrom;
533 auto acknowledgment =
539 if (acknowledgment->stationsSendBlockAckReqTo.contains(psdu.second->GetAddr1()))
542 std::set<uint8_t> tids = psdu.second->GetTids();
544 "Acknowledgment method incompatible with a Multi-TID A-MPDU");
545 uint8_t tid = *tids.begin();
549 m_mac->GetQosTxop(tid)->PrepareBlockAckRequest(psdu.second->GetAddr1(), tid);
550 m_edca->GetBaManager()->ScheduleBar(reqHdr, hdr);
554 if (!acknowledgment->stationsReplyingWithNormalAck.empty())
559 &acknowledgment->stationsReplyingWithNormalAck.begin()->second.ackTxVector;
560 auto from = acknowledgment->stationsReplyingWithNormalAck.begin()->first;
563 mpdu = *psdu->begin();
564 staExpectResponseFrom.insert(from);
566 else if (!acknowledgment->stationsReplyingWithBlockAck.empty())
571 &acknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
572 auto from = acknowledgment->stationsReplyingWithBlockAck.begin()->first;
574 staExpectResponseFrom.insert(from);
590 std::map<uint16_t, CtrlBAckRequestHeader> recipients;
592 NS_ASSERT(!acknowledgment->stationsReplyingWithBlockAck.empty());
593 auto staIt = acknowledgment->stationsReplyingWithBlockAck.begin();
595 while (staIt != acknowledgment->stationsReplyingWithBlockAck.end())
601 staIt->second.blockAckTxVector.GetHeMuUserInfo(staId));
602 recipients.emplace(staId, staIt->second.barHeader);
617 for (
auto& station : acknowledgment->stationsReplyingWithBlockAck)
619 staExpectResponseFrom.insert(station.first);
624 acknowledgment->muBarTxVector,
625 m_phy->GetPhyBand());
627 *acknowledgment->acknowledgmentTime -= (
m_phy->GetSifs() + txDuration);
631 &acknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
637 staExpectResponseFrom,
641 staExpectResponseFrom.size());
662 acknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
665 for (
auto& station : acknowledgment->stationsReplyingWithBlockAck)
667 staExpectResponseFrom.insert(station.first);
670 auto psduMapIt = std::find_if(
m_psduMap.begin(),
673 return psdu.second->GetAddr1() == station.first;
678 std::vector<Ptr<WifiMpdu>> mpduList(psduMapIt->second->begin(),
679 psduMapIt->second->end());
680 NS_ASSERT(mpduList.size() == psduMapIt->second->GetNMpdus());
683 station.second.blockAckTxVector.SetLength(acknowledgment->ulLength);
684 mpduList.push_back(
PrepareMuBar(station.second.blockAckTxVector,
685 {{psduMapIt->first, station.second.barHeader}}));
689 station.second.blockAckTxVector.GetHeMuUserInfo(psduMapIt->first));
694 &acknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
704 mpdu = *m_psduMap.begin()->second->begin();
706 auto acknowledgment =
static_cast<WifiUlMuMultiStaBa*
>(m_txParams.m_acknowledgment.get());
709 for (
const auto& station : acknowledgment->stationsReceivingMultiStaBa)
711 staExpectResponseFrom.insert(station.first.first);
717 acknowledgment->baType.m_bitmapLen.clear();
719 timerType = WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF;
720 responseTxVector = &acknowledgment->tbPpduTxVector;
721 m_trigVector = GetTrigVector(m_muScheduler->GetUlMuInfo(m_linkId).trigger);
726 else if (m_txParams.m_acknowledgment->method == WifiAcknowledgment::NONE &&
727 !m_txParams.m_txVector.IsUlMu() &&
IsTrigger(m_psduMap))
729 CtrlTriggerHeader& trigger = m_muScheduler->GetUlMuInfo(m_linkId).trigger;
734 for (
const auto& userInfo : trigger)
736 auto staIt = m_apMac->GetStaList(m_linkId).find(userInfo.GetAid12());
737 NS_ASSERT(staIt != m_apMac->GetStaList(m_linkId).end());
738 staExpectResponseFrom.insert(staIt->second);
741 timerType = WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF;
742 txVector = trigger.GetHeTbTxVector(trigger.begin()->GetAid12());
743 responseTxVector = &txVector;
744 m_trigVector = GetTrigVector(m_muScheduler->GetUlMuInfo(m_linkId).trigger);
749 else if (m_txParams.m_txVector.IsUlMu() &&
750 m_txParams.m_acknowledgment->method == WifiAcknowledgment::ACK_AFTER_TB_PPDU)
753 timerType = WifiTxTimer::WAIT_BLOCK_ACK_AFTER_TB_PPDU;
754 NS_ASSERT(m_staMac && m_staMac->IsAssociated());
755 auto recv = m_psduMap.begin()->second->GetAddr1();
756 txVector = GetWifiRemoteStationManager()->GetBlockAckTxVector(recv, m_txParams.m_txVector);
757 responseTxVector = &txVector;
758 staExpectResponseFrom.insert(recv);
763 else if (m_txParams.m_txVector.IsUlMu() &&
764 m_txParams.m_acknowledgment->method == WifiAcknowledgment::NONE)
770 NS_ABORT_MSG(
"Unable to handle the selected acknowledgment method ("
771 << m_txParams.m_acknowledgment.get() <<
")");
776 for (
const auto& psdu : m_psduMap)
778 psduMap.emplace(psdu.first, psdu.second);
782 if (m_txParams.m_txVector.IsUlMu())
784 txDuration = HePhy::ConvertLSigLengthToHeTbPpduDuration(m_txParams.m_txVector.GetLength(),
785 m_txParams.m_txVector,
786 m_phy->GetPhyBand());
791 WifiPhy::CalculateTxDuration(psduMap, m_txParams.m_txVector, m_phy->GetPhyBand());
794 Time durationId = GetPsduDurationId(txDuration, m_txParams);
796 if (m_continueTxopAfterBsrpTf && m_edca && m_edca->GetTxopLimit(m_linkId).IsZero() &&
797 timerType == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF)
801 durationId += m_muScheduler->GetExtraTimeForBsrpTfDurationId(m_linkId);
804 for (
auto& psdu : m_psduMap)
806 psdu.second->SetDuration(durationId);
810 if (timerType == WifiTxTimer::NOT_RUNNING)
815 Simulator::Schedule(txDuration + m_phy->GetSifs(),
816 &HeFrameExchangeManager::SendPsduMap,
819 else if (!m_txParams.m_txVector.IsUlMu())
821 Simulator::Schedule(txDuration, &HeFrameExchangeManager::TransmissionSucceeded,
this);
826 Time timeout = txDuration + m_phy->GetSifs() + m_phy->GetSlot() +
827 WifiPhy::CalculatePhyPreambleAndHeaderDuration(*responseTxVector);
828 m_channelAccessManager->NotifyAckTimeoutStartNow(
timeout);
833 case WifiTxTimer::WAIT_NORMAL_ACK_AFTER_DL_MU_PPDU:
835 m_txTimer.Set(timerType,
837 staExpectResponseFrom,
838 &HeFrameExchangeManager::NormalAckTimeout,
841 m_txParams.m_txVector);
843 case WifiTxTimer::WAIT_BLOCK_ACK:
845 m_txTimer.Set(timerType,
847 staExpectResponseFrom,
848 &HeFrameExchangeManager::BlockAckTimeout,
851 m_txParams.m_txVector);
853 case WifiTxTimer::WAIT_BLOCK_ACKS_IN_TB_PPDU:
854 m_txTimer.Set(timerType,
856 staExpectResponseFrom,
857 &HeFrameExchangeManager::BlockAcksInTbPpduTimeout,
860 staExpectResponseFrom.size());
862 case WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF:
863 case WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF:
864 m_txTimer.Set(timerType,
866 staExpectResponseFrom,
867 &HeFrameExchangeManager::TbPpduTimeout,
870 staExpectResponseFrom.size());
872 case WifiTxTimer::WAIT_BLOCK_ACK_AFTER_TB_PPDU:
873 m_txTimer.Set(timerType,
875 staExpectResponseFrom,
876 &HeFrameExchangeManager::BlockAckAfterTbPpduTimeout,
878 m_psduMap.begin()->second,
879 m_txParams.m_txVector);
888 ForwardPsduMapDown(psduMap, m_txParams.m_txVector);
890 if (timerType == WifiTxTimer::WAIT_BLOCK_ACKS_IN_TB_PPDU ||
891 timerType == WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF ||
892 timerType == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF)
895 auto hePhy = StaticCast<HePhy>(m_phy->GetPhyEntity(responseTxVector->GetModulationClass()));
896 hePhy->SetTrigVector(m_trigVector, m_txTimer.GetDelayLeft());
898 else if (timerType == WifiTxTimer::NOT_RUNNING &&
899 (m_txParams.m_txVector.IsUlMu() ||
900 m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE))
904 Simulator::Schedule(txDuration, &WifiPsduMap::clear, &m_psduMap);
907 if (m_txTimer.IsRunning() && timerType != WifiTxTimer::WAIT_BLOCK_ACK_AFTER_TB_PPDU)
913 for (
const auto& address : staExpectResponseFrom)
915 if (!GetWifiRemoteStationManager()->GetEmlsrEnabled(address) ||
916 timerType == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF ||
917 m_protectedStas.contains(address))
919 m_sentFrameTo.insert(address);
933 auto sigBMode = hePhy->GetSigBMode(txVector);
937 for (
const auto& psdu : psduMap)
939 NS_LOG_DEBUG(
"Transmitting: [STAID=" << psdu.first <<
", " << *psdu.second <<
"]");
942 for (
const auto& [staId, psdu] : psduMap)
949 if (psduMap.size() > 1 || psduMap.begin()->second->IsAggregate() ||
950 psduMap.begin()->second->IsSingle())
956 SetTxNav(*psduMap.cbegin()->second->begin(), txDuration);
958 m_phy->Send(psduMap, txVector);
963 std::map<uint16_t, CtrlBAckRequestHeader> recipients)
const
976 for (
auto& userInfo : muBar)
978 auto recipientIt = recipients.find(userInfo.GetAid12());
979 NS_ASSERT(recipientIt != recipients.end());
982 userInfo.SetMuBarTriggerDepUserInfo(recipientIt->second);
986 bar->AddHeader(muBar);
999 rxAddress =
m_apMac->GetStaList(
m_linkId).at(recipients.begin()->first);
1028 muRtsCtsProtection->muRts.begin()->GetAid12());
1032 muRtsCtsProtection->protectionTime =
1034 muRtsCtsProtection->muRtsTxVector,
1035 m_phy->GetPhyBand()) +
1037 2 *
m_phy->GetSifs();
1061 NS_ABORT_IF(dlMuBarBaAcknowledgment->stationsReplyingWithNormalAck.size() +
1062 dlMuBarBaAcknowledgment->stationsReplyingWithBlockAck.size() >
1065 if (!dlMuBarBaAcknowledgment->stationsReplyingWithNormalAck.empty())
1068 dlMuBarBaAcknowledgment->stationsReplyingWithNormalAck.begin()->second;
1074 if (!dlMuBarBaAcknowledgment->stationsReplyingWithBlockAck.empty())
1077 dlMuBarBaAcknowledgment->stationsReplyingWithBlockAck.begin()->second;
1080 info.blockAckTxVector,
1081 m_phy->GetPhyBand());
1084 for (
const auto& stations : dlMuBarBaAcknowledgment->stationsSendBlockAckReqTo)
1086 const auto& info = stations.second;
1087 duration +=
m_phy->GetSifs() +
1089 info.blockAckReqTxVector,
1090 m_phy->GetPhyBand()) +
1093 info.blockAckTxVector,
1094 m_phy->GetPhyBand());
1097 dlMuBarBaAcknowledgment->acknowledgmentTime = duration;
1104 auto dlMuTfMuBarAcknowledgment =
static_cast<WifiDlMuTfMuBar*
>(acknowledgment);
1108 for (
const auto& stations : dlMuTfMuBarAcknowledgment->stationsReplyingWithBlockAck)
1111 const auto& info = stations.second;
1112 NS_ASSERT(info.blockAckTxVector.GetHeMuUserInfoMap().size() == 1);
1113 uint16_t staId = info.blockAckTxVector.GetHeMuUserInfoMap().begin()->first;
1115 info.blockAckTxVector,
1116 m_phy->GetPhyBand(),
1119 if (currBlockAckDuration > duration)
1121 duration = currBlockAckDuration;
1127 WifiTxVector& txVector = dlMuTfMuBarAcknowledgment->stationsReplyingWithBlockAck.begin()
1128 ->second.blockAckTxVector;
1129 std::tie(dlMuTfMuBarAcknowledgment->ulLength, duration) =
1137 dlMuTfMuBarAcknowledgment->muBarTxVector.GetChannelWidth(),
1138 dlMuTfMuBarAcknowledgment->barTypes);
1139 if (dlMuTfMuBarAcknowledgment->muBarTxVector.GetModulationClass() >=
WIFI_MOD_CLASS_VHT)
1144 dlMuTfMuBarAcknowledgment->acknowledgmentTime =
1147 dlMuTfMuBarAcknowledgment->muBarTxVector,
1148 m_phy->GetPhyBand()) +
1149 m_phy->GetSifs() + duration;
1160 for (
const auto& stations : dlMuAggrTfAcknowledgment->stationsReplyingWithBlockAck)
1163 const auto& info = stations.second;
1164 NS_ASSERT(info.blockAckTxVector.GetHeMuUserInfoMap().size() == 1);
1165 uint16_t staId = info.blockAckTxVector.GetHeMuUserInfoMap().begin()->first;
1167 info.blockAckTxVector,
1168 m_phy->GetPhyBand(),
1171 if (currBlockAckDuration > duration)
1173 duration = currBlockAckDuration;
1180 dlMuAggrTfAcknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
1181 std::tie(dlMuAggrTfAcknowledgment->ulLength, duration) =
1183 dlMuAggrTfAcknowledgment->acknowledgmentTime =
m_phy->GetSifs() + duration;
1193 ulMuMultiStaBa->multiStaBaTxVector,
1194 m_phy->GetPhyBand());
1195 ulMuMultiStaBa->acknowledgmentTime =
m_phy->GetSifs() + duration;
1224 uint16_t staId)
const
1229 NS_ASSERT_MSG(userInfoIt != trigger.
end(),
"User Info field for AID=" << staId <<
" not found");
1232 if (uint8_t ru = userInfoIt->GetMuRtsRuAllocation(); ru < 65)
1256 txVector.SetChannelWidth(bw);
1279 NS_ASSERT_MSG(psduInfo,
"No information for " << receiver <<
" in TX params");
1280 NS_ASSERT_MSG(!psduInfo->seqNumbers.empty(),
"No sequence number for " << receiver);
1281 const auto tid = psduInfo->seqNumbers.cbegin()->first;
1289 {m_mac->GetBarTypeAsOriginator(receiver, tid)}),
1297 m_phy->GetPhyBand(),
1312 std::size_t nSolicitedStations,
1313 bool updateFailedCw)
1315 const auto& staMissedTbPpduFrom =
m_txTimer.GetStasExpectedToRespond();
1316 NS_LOG_FUNCTION(
this << psduMap << staMissedTbPpduFrom.size() << nSolicitedStations
1323 NS_ASSERT(!staMissedTbPpduFrom.empty());
1326 if (staMissedTbPpduFrom.size() == nSolicitedStations)
1330 psduMap->cbegin()->second->GetPayload(0)->PeekHeader(trigger);
1349 for (
const auto& address : staMissedTbPpduFrom)
1351 NS_LOG_DEBUG(address <<
" did not respond, hence it is no longer protected");
1367 std::size_t nSolicitedStations)
1377 const auto& staMissedBlockAckFrom =
m_txTimer.GetStasExpectedToRespond();
1378 NS_ASSERT(!staMissedBlockAckFrom.empty());
1380 if (staMissedBlockAckFrom.size() == nSolicitedStations)
1392 for (
const auto& sta : staMissedBlockAckFrom)
1401 if (staMissedBlockAckFrom.size() == nSolicitedStations)
1445 if (mpdu->IsQueued())
1447 m_mac->GetTxopQueue(mpdu->GetQueueAc())->GetOriginal(mpdu)->GetHeader().SetRetry();
1469 if (mpdu->IsQueued())
1471 mpdu->GetHeader().SetRetry();
1487 for (
const auto& userInfoField : trigger)
1490 userInfoField.GetAid12(),
1491 {userInfoField.GetRuAllocation(), userInfoField.GetUlMcs(), userInfoField.GetNss()});
1503 uint16_t staId =
m_staMac->GetAssociationId();
1510 NS_ASSERT_MSG(heConfiguration,
"This STA has to be an HE station to send an HE TB PPDU");
1513 if (userInfoIt->IsUlTargetRssiMaxTxPower())
1515 NS_LOG_LOGIC(
"AP requested using the max transmit power (" <<
m_phy->GetTxPowerEnd()
1545 auto reqTxPower =
dBm_u{
static_cast<double>(userInfoIt->GetUlTargetRssi() + pathLossDb)};
1548 uint8_t numPowerLevels =
m_phy->GetNTxPower();
1549 if (numPowerLevels > 1)
1551 dBm_u step = (
m_phy->GetTxPowerEnd() -
m_phy->GetTxPowerStart()) / (numPowerLevels - 1);
1552 powerLevel =
static_cast<uint8_t
>(
1553 ceil((reqTxPower -
m_phy->GetTxPowerStart()) /
1555 if (powerLevel > numPowerLevels)
1557 powerLevel = numPowerLevels;
1560 if (reqTxPower >
m_phy->GetPower(powerLevel))
1562 NS_LOG_WARN(
"The requested power level (" << reqTxPower <<
"dBm) cannot be satisfied (max: "
1563 <<
m_phy->GetTxPowerEnd() <<
"dBm)");
1567 <<
"{pathLoss=" << pathLossDb <<
"dB, reqTxPower=" << reqTxPower <<
"dBm}"
1569 <<
"{powerLevel=" << +powerLevel <<
" -> " <<
m_phy->GetPower(powerLevel) <<
"dBm}"
1570 <<
" PHY power capa "
1571 <<
"{min=" <<
m_phy->GetTxPowerStart() <<
"dBm, max=" <<
m_phy->GetTxPowerEnd()
1572 <<
"dBm, levels:" << +numPowerLevels <<
"}");
1591 for (
auto& userInfo : trigger)
1594 auto itAidAddr = staList.find(userInfo.GetAid12());
1598 auto rssi =
static_cast<int8_t>(*optRssi);
1599 rssi = (rssi >= -20)
1601 : ((rssi <= -110) ? -110 : rssi);
1602 userInfo.SetUlTargetRssi(rssi);
1611 auto txVectorCopy = txVector;
1613 if (psdu->GetNMpdus() == 1 && psdu->GetHeader(0).IsTrigger())
1616 psdu->GetPayload(0)->PeekHeader(trigger);
1660 NS_LOG_DEBUG(
"UL MU CS indicated medium busy, cannot send CTS");
1681 NS_ASSERT(!acknowledgment->stationsReceivingMultiStaBa.empty());
1684 blockAck.
SetType(acknowledgment->baType);
1688 for (
const auto& staInfo : acknowledgment->stationsReceivingMultiStaBa)
1690 receiver = staInfo.first.first;
1691 uint8_t tid = staInfo.first.second;
1692 std::size_t index = staInfo.second;
1700 NS_LOG_DEBUG(
"Multi-STA Block Ack: Sending All-ack to=" << receiver);
1705 if (acknowledgment->baType.m_bitmapLen.at(index) == 0)
1708 NS_LOG_DEBUG(
"Multi-STA Block Ack: Sending Ack to=" << receiver);
1716 auto agreement =
m_mac->GetBaAgreementEstablishedAsRecipient(receiver, tid);
1718 agreement->get().FillBlockAckBitmap(blockAck, index);
1719 NS_LOG_DEBUG(
"Multi-STA Block Ack: Sending Block Ack with seq="
1721 <<
" tid=" << +tid);
1727 hdr.
SetAddr1(acknowledgment->stationsReceivingMultiStaBa.size() == 1
1735 packet->AddHeader(blockAck);
1740 acknowledgment->multiStaBaTxVector,
1741 m_phy->GetPhyBand());
1753 const auto singleDurationId =
Max(durationId -
m_phy->GetSifs() - txDuration,
Seconds(0));
1756 psdu->SetDuration(singleDurationId);
1765 psdu->SetDuration(duration);
1768 psdu->GetPayload(0)->AddPacketTag(
m_muSnrTag);
1787 NS_LOG_DEBUG(
"Received a Trigger Frame (basic variant) soliciting a transmission");
1800 std::vector<uint8_t> tids;
1801 uint16_t staId =
m_staMac->GetAssociationId();
1804 for (uint8_t i = 0; i < 4; i++)
1807 tids.push_back(acIt->second.GetHighTid());
1808 tids.push_back(acIt->second.GetLowTid());
1822 m_phy->GetPhyBand());
1824 for (
const auto& tid : tids)
1828 if (!
m_mac->GetBaAgreementEstablishedAsOriginator(hdr.
GetAddr2(), tid))
1838 if (
auto mpdu =
GetBar(edca->GetAccessCategory(), tid, hdr.
GetAddr2());
1839 mpdu &&
TryAddMpdu(mpdu, txParams, ppduDuration))
1849 if (
auto mpdu = edca->PeekNextMpdu(
m_linkId, tid, receiver))
1852 if (
auto item = edca->GetNextMpdu(
m_linkId, mpdu, txParams, ppduDuration,
false))
1855 std::vector<Ptr<WifiMpdu>> mpduList =
1912 m_phy->GetPhyBand());
1915 std::vector<Ptr<WifiMpdu>> mpduList;
1917 for (uint8_t tid = 0; tid < 8; ++tid)
1919 if (!
m_mac->GetBaAgreementEstablishedAsOriginator(hdr.
GetAddr2(), tid))
1921 NS_LOG_DEBUG(
"Skipping tid=" << +tid <<
" because no agreement established");
1945 NS_LOG_DEBUG(
"Aggregating a QoS Null frame with tid=" << +tid);
1947 mpduList.push_back(mpdu);
1950 if (mpduList.empty())
1952 NS_LOG_DEBUG(
"Not enough time to send a QoS Null frame");
1958 uint16_t staId =
m_staMac->GetAssociationId();
1970 auto agreement =
m_mac->GetBaAgreementEstablishedAsRecipient(
m_bssid, tid);
1974 NS_LOG_DEBUG(
"There's not a valid agreement for this BlockAckReq");
2026 if (bssid != empty && bssid !=
m_bssid)
2034 if (bssid == empty && ta != empty && ra != empty && ta !=
m_bssid && ra !=
m_bssid)
2047 const auto bssColor =
m_mac->GetHeConfiguration()->m_bssColor;
2050 return bssColor != 0 && bssColor == txVector.
GetBssColor();
2056 const Time& surplus)
2077 NS_LOG_DEBUG(
"PPDU not classified as intra-BSS, update the basic NAV");
2082 NS_LOG_DEBUG(
"PPDU classified as intra-BSS, update the intra-BSS NAV");
2085 duration += surplus;
2093 NS_LOG_DEBUG(
"Received CF-End, resetting the intra-BSS NAV");
2120 auto navResetDelay =
2121 2 *
m_phy->GetSifs() +
2168std::optional<Mac48Address>
2181 return std::nullopt;
2216 "No User Info field for STA (" <<
m_self
2217 <<
") AID=" <<
m_staMac->GetAssociationId());
2219 std::set<uint8_t> indices;
2224 auto bw = ctsTxVector.GetChannelWidth();
2225 indices =
m_phy->GetOperatingChannel().GetAll20MHzChannelIndicesInPrimary(bw);
2230 m_phy->GetOperatingChannel().Get20MHzIndicesCoveringRu(userInfoIt->GetRuAllocation(),
2242 NS_LOG_FUNCTION(
this << *mpdu << rxSignalInfo << txVector << inAmpdu);
2245 NS_ASSERT(mpdu->GetHeader().GetAddr1().IsGroup() || mpdu->GetHeader().GetAddr1() ==
m_self);
2258 if (!
m_txTimer.GetStasExpectedToRespond().contains(sender))
2260 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2266 NS_LOG_DEBUG(
"Received a BlockAckReq in a TB PPDU from " << sender);
2269 mpdu->GetPacket()->PeekHeader(blockAckReq);
2273 m_mac->GetMldAddress(sender).value_or(sender),
2278 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, tid), index);
2279 acknowledgment->baType.m_bitmapLen.push_back(
2280 m_mac->GetBaTypeAsRecipient(sender, tid).m_bitmapLen.at(0));
2286 NS_LOG_DEBUG(
"Received an S-MPDU in a TB PPDU from " << sender <<
" (" << *mpdu <<
")");
2292 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, tid), index);
2293 acknowledgment->baType.m_bitmapLen.push_back(0);
2309 if (!acknowledgment->stationsReceivingMultiStaBa.empty() && !
m_multiStaBaEvent.IsPending())
2315 mpdu->GetHeader().GetDuration());
2321 if (
m_txTimer.GetStasExpectedToRespond().empty())
2345 const auto& sender = hdr.
GetAddr2();
2347 if (!
m_txTimer.GetStasExpectedToRespond().contains(sender))
2349 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2354 NS_LOG_WARN(
"No QoS Null frame in the received MPDU");
2358 NS_LOG_DEBUG(
"Received a QoS Null frame in a TB PPDU from " << sender);
2377 mpdu->GetPacket()->PeekPacketTag(tag);
2394 NS_LOG_DEBUG(
"Received a CTS frame in response to an MU-RTS");
2408 auto acknowledgment =
2410 NS_ASSERT(acknowledgment->stationsReplyingWithNormalAck.size() == 1);
2412 uint16_t staId =
m_apMac->GetAssociationId(
2413 acknowledgment->stationsReplyingWithNormalAck.begin()->first,
2418 acknowledgment->stationsReplyingWithNormalAck.begin()->first);
2420 mpdu->GetPacket()->PeekPacketTag(tag);
2438 NS_LOG_DEBUG(
"Received BlockAck in TB PPDU from=" << sender);
2441 mpdu->GetPacket()->PeekPacketTag(tag);
2445 mpdu->GetPacket()->PeekHeader(blockAck);
2447 std::pair<uint16_t, uint16_t> ret =
2450 m_mac->GetMldAddress(sender).value_or(sender),
2460 if (!
m_txTimer.GetStasExpectedToRespond().contains(sender))
2462 NS_LOG_WARN(
"Received a BlockAck from an unexpected stations: " << sender);
2468 if (
m_txTimer.GetStasExpectedToRespond().empty())
2488 mpdu->GetPacket()->PeekHeader(blockAck);
2491 "A Multi-STA BlockAck is expected after a TB PPDU");
2498 NS_LOG_DEBUG(
"The sender is not the AP we are associated with");
2502 uint16_t staId =
m_staMac->GetAssociationId();
2505 if (indices.empty())
2507 NS_LOG_DEBUG(
"No Per AID TID Info subfield intended for me");
2512 mpdu->GetPacket()->PeekPacketTag(tag);
2515 for (
const auto& index : indices)
2533 std::set<uint8_t> tids =
m_psduMap.at(staId)->GetTids();
2534 NS_ABORT_MSG_IF(tids.size() > 1,
"Multi-TID A-MPDUs not supported yet");
2535 tid = *tids.begin();
2538 std::pair<uint16_t, uint16_t> ret =
GetBaManager(tid)->NotifyGotBlockAck(
2552 if (
m_psduMap.at(staId)->GetHeader(0).IsQosData() &&
2554 || std::any_of(blockAck.
GetBitmap(index).begin(),
2556 [](uint8_t b) { return b != 0; })))
2572 for (
const auto& [staId, psdu] :
m_psduMap)
2574 if (psdu->GetNMpdus() == 1 && psdu->GetHeader(0).IsBlockAckReq())
2606 mpdu->GetPacket()->PeekHeader(trigger);
2617 uint16_t staId =
m_staMac->GetAssociationId();
2622 NS_LOG_DEBUG(
"Received MU-RTS Trigger Frame from=" << sender);
2643 NS_LOG_DEBUG(
"Received MU-BAR Trigger Frame from=" << sender);
2653 m_mac->GetMldAddress(sender).value_or(sender),
2673 else if (trigger.
IsBsrp())
2701 const std::vector<bool>& perMpduStatus)
2703 std::set<uint8_t> tids = psdu->GetTids();
2714 if (!
m_txTimer.GetStasExpectedToRespond().contains(sender))
2716 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2720 NS_LOG_DEBUG(
"Received an A-MPDU in a TB PPDU from " << sender <<
" (" << *psdu <<
")");
2722 if (std::any_of(tids.begin(), tids.end(), [&psdu](uint8_t tid) {
2723 return psdu->GetAckPolicyForTid(tid) == WifiMacHeader::NORMAL_ACK;
2726 if (std::all_of(perMpduStatus.cbegin(), perMpduStatus.cend(), [](
bool v) { return v; }))
2729 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, 14),
2731 acknowledgment->baType.m_bitmapLen.push_back(0);
2737 for (
const auto& tid : tids)
2739 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, tid),
2741 acknowledgment->baType.m_bitmapLen.push_back(
2742 m_mac->GetBaTypeAsRecipient(sender, tid).m_bitmapLen.at(0));
2750 if (!acknowledgment->stationsReceivingMultiStaBa.empty() && !
m_multiStaBaEvent.IsPending())
2756 psdu->GetDuration());
2762 if (
m_txTimer.GetStasExpectedToRespond().empty())
2787 if (!
m_txTimer.GetStasExpectedToRespond().contains(sender))
2789 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2792 if (std::none_of(psdu->begin(), psdu->end(), [](
Ptr<WifiMpdu> mpdu) {
2793 return mpdu->GetHeader().IsQosData() && !mpdu->GetHeader().HasData();
2796 NS_LOG_WARN(
"No QoS Null frame in the received PSDU");
2800 NS_LOG_DEBUG(
"Received QoS Null frames in a TB PPDU from " << sender);
2810 auto psduIt = psdu->begin();
2811 while (psduIt != psdu->end())
2813 if ((*psduIt)->GetHeader().IsTrigger())
2815 ReceiveMpdu(*psduIt, rxSignalInfo, txVector,
false);
2839 if (
m_txTimer.GetStasExpectedToRespond().empty())
static WifiMode GetErpOfdmRate6Mbps()
Return a WifiMode for ERP-OFDM at 6 Mbps.
std::set< Mac48Address > m_sentRtsTo
the STA(s) which we sent an RTS to (waiting for CTS)
uint8_t m_linkId
the ID of the link this object is associated with
Ptr< WifiMac > m_mac
the MAC layer on this station
void SetTxNav(Ptr< const WifiMpdu > mpdu, const Time &txDuration)
Set the TXNAV upon sending an MPDU.
bool m_protectedIfResponded
whether a STA is assumed to be protected if replied to a frame requiring acknowledgment
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager() const
void UpdateTxDuration(Mac48Address receiver, WifiTxParameters &txParams) const
Update the TX duration field of the given TX parameters after that the PSDU addressed to the given re...
virtual void CalculateAcknowledgmentTime(WifiAcknowledgment *acknowledgment) const
Calculate the time required to acknowledge a frame according to the given acknowledgment method.
virtual void Reset()
Reset this frame exchange manager.
Mac48Address m_self
the MAC address of this device
virtual void StartProtection(const WifiTxParameters &txParams)
Start the protection mechanism indicated by the given TX parameters.
WifiTxTimer m_txTimer
the timer set upon frame transmission
std::set< Mac48Address > m_protectedStas
STAs that have replied to an RTS in this TXOP.
virtual Time GetRtsDurationId(const WifiTxVector &rtsTxVector, Time txDuration, Time response) const
Compute how to set the Duration/ID field of an RTS frame to send to protect a frame transmitted with ...
virtual void ProtectionCompleted()
Transmit prepared frame immediately, if no protection was used, or in a SIFS, if protection was compl...
virtual void NotifyChannelReleased(Ptr< Txop > txop)
Notify the given Txop that channel has been released.
virtual void NormalAckTimeout(Ptr< WifiMpdu > mpdu, const WifiTxVector &txVector)
Called when the Ack timeout expires.
virtual void CtsTimeout(Ptr< WifiMpdu > rts, const WifiTxVector &txVector)
Called when the CTS timeout expires.
void DoCtsTimeout(const WifiPsduMap &psduMap)
Take required actions when the CTS timer fired after sending an (MU-)RTS to protect the given PSDU ma...
Time m_txNav
the TXNAV timer
virtual void CalculateProtectionTime(WifiProtection *protection) const
Calculate the time required to protect a frame according to the given protection method.
Ptr< WifiAckManager > GetAckManager() const
Get the Acknowledgment Manager used by this node.
virtual void EndReceiveAmpdu(Ptr< const WifiPsdu > psdu, const RxSignalInfo &rxSignalInfo, const WifiTxVector &txVector, const std::vector< bool > &perMpduStatus)
This method is called when the reception of an A-MPDU including multiple MPDUs is completed.
virtual void TransmissionSucceeded()
Take necessary actions upon a transmission success.
EventId m_sendCtsEvent
the event to send a CTS after an (MU-)RTS
Ptr< WifiPhy > m_phy
the PHY layer on this station
std::set< Mac48Address > m_sentFrameTo
the STA(s) to which we sent a frame requesting a response
void DoSendCtsAfterRts(const WifiMacHeader &rtsHdr, WifiTxVector &ctsTxVector, double rtsSnr)
Send CTS after receiving RTS.
Ptr< ApWifiMac > m_apMac
AP MAC layer pointer (null if not an AP)
Mac48Address m_bssid
BSSID address (Mac48Address)
virtual void PostProcessFrame(Ptr< const WifiPsdu > psdu, const WifiTxVector &txVector)
Perform actions that are possibly needed after receiving any frame, independently of whether the fram...
Ptr< ChannelAccessManager > m_channelAccessManager
the channel access manager
virtual void ReceivedNormalAck(Ptr< WifiMpdu > mpdu, const WifiTxVector &txVector, const WifiTxVector &ackTxVector, const RxSignalInfo &rxInfo, double snr)
Perform the actions needed when a Normal Ack is received.
virtual void ReceiveMpdu(Ptr< const WifiMpdu > mpdu, RxSignalInfo rxSignalInfo, const WifiTxVector &txVector, bool inAmpdu)
This method handles the reception of an MPDU (possibly included in an A-MPDU)
MHz_u m_allowedWidth
the allowed width for the current transmission
Time m_navEnd
NAV expiration time.
virtual void UpdateNav(const WifiMacHeader &hdr, const WifiTxVector &txVector, const Time &surplus=Time{0})
Update the NAV, if needed, based on the Duration/ID of the given MAC header and the given surplus.
Ptr< StaWifiMac > m_staMac
STA MAC layer pointer (null if not a STA)
virtual void RxStartIndication(WifiTxVector txVector, Time psduDuration)
EventId m_navResetEvent
the event to reset the NAV after an RTS
virtual Time GetTxDuration(uint32_t ppduPayloadSize, Mac48Address receiver, const WifiTxParameters &txParams) const
Get the updated TX duration of the frame associated with the given TX parameters if the size of the P...
WifiTxVector GetTrigVector(const CtrlTriggerHeader &trigger) const
Get the TRIGVECTOR that the MAC has to pass to the PHY when transmitting the given Trigger Frame.
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...
void ReceiveMuBarTrigger(const CtrlTriggerHeader &trigger, uint8_t tid, Time durationId, double snr)
Respond to a MU-BAR Trigger Frame (if permitted by UL MU CS mechanism).
virtual void SendQosNullFramesInTbPpdu(const CtrlTriggerHeader &trigger, const WifiMacHeader &hdr)
Send QoS Null frames in response to a Basic or BSRP Trigger Frame.
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 IntraBssNavResetTimeout()
Reset the intra-BSS NAV upon expiration of the intra-BSS NAV reset timer.
virtual void SendMuRts(const WifiTxParameters &txParams)
Send an MU-RTS to begin an MU-RTS/CTS frame exchange protecting an MU PPDU.
virtual void ReceivedQosNullAfterBsrpTf(Mac48Address sender)
Perform the actions required when receiving QoS Null frame(s) from the given sender after a BSRP Trig...
WifiTxParameters m_txParams
the TX parameters for the current PPDU
Time GetTxDuration(uint32_t ppduPayloadSize, Mac48Address receiver, const WifiTxParameters &txParams) const override
Get the updated TX duration of the frame associated with the given TX parameters if the size of the P...
void BlockAckTimeout(Ptr< WifiPsdu > psdu, const WifiTxVector &txVector) override
Called when the BlockAck timeout expires.
void RxStartIndication(WifiTxVector txVector, Time psduDuration) override
void CalculateAcknowledgmentTime(WifiAcknowledgment *acknowledgment) const override
Calculate the time required to acknowledge a frame according to the given acknowledgment method.
Ptr< WifiMpdu > m_triggerFrame
Trigger Frame being sent.
std::optional< Mac48Address > FindTxopHolder(const WifiMacHeader &hdr, const WifiTxVector &txVector) override
Determine the holder of the TXOP, if possible, based on the received frame.
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...
bool m_triggerFrameInAmpdu
True if the received A-MPDU contains an MU-BAR.
bool m_continueTxopAfterBsrpTf
whether to continue a TXOP a SIFS after the reception of responses to a BSRP TF when TXOP limit is ze...
Ptr< MultiUserScheduler > m_muScheduler
Multi-user Scheduler (HE APs only)
virtual void CtsAfterMuRtsTimeout(Ptr< WifiMpdu > muRts, const WifiTxVector &txVector)
Called when no CTS frame is received after an MU-RTS.
void NavResetTimeout() override
Reset the NAV upon expiration of the NAV reset timer.
bool IsIntraBssPpdu(const WifiMacHeader &hdr, const WifiTxVector &txVector) const
Return whether the received frame is classified as intra-BSS.
WifiTxVector m_trigVector
the TRIGVECTOR
void ProtectionCompleted() override
Transmit prepared frame immediately, if no protection was used, or in a SIFS, if protection was compl...
virtual void SetTargetRssi(CtrlTriggerHeader &trigger) const
Set the UL Target RSSI subfield of every User Info fields of the given Trigger Frame to the most rece...
virtual void SendCtsAfterMuRts(const WifiMacHeader &muRtsHdr, const CtrlTriggerHeader &trigger, double muRtsSnr)
Send CTS after receiving an MU-RTS.
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,...
void EndReceiveAmpdu(Ptr< const WifiPsdu > psdu, const RxSignalInfo &rxSignalInfo, const WifiTxVector &txVector, const std::vector< bool > &perMpduStatus) override
This method is called when the reception of an A-MPDU including multiple MPDUs is completed.
void CalculateProtectionTime(WifiProtection *protection) const override
Calculate the time required to protect a frame according to the given protection method.
bool VirtualCsMediumIdle() const override
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.
MuSnrTag m_muSnrTag
Tag to attach to Multi-STA BlockAck frames.
void ReceiveMpdu(Ptr< const WifiMpdu > mpdu, RxSignalInfo rxSignalInfo, const WifiTxVector &txVector, bool inAmpdu) override
This method handles the reception of an MPDU (possibly included in an A-MPDU)
EventId m_intraBssNavResetEvent
the event to reset the intra-BSS NAV after an RTS
virtual void ForwardPsduMapDown(WifiConstPsduMap psduMap, WifiTxVector &txVector)
Forward a map of PSDUs 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 ClearTxopHolderIfNeeded() override
Clear the TXOP holder if the intra-BSS NAV counted down to zero (includes the case of intra-BSS NAV r...
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.
void PostProcessFrame(Ptr< const WifiPsdu > psdu, const WifiTxVector &txVector) override
Perform actions that are possibly needed after receiving any frame, independently of whether the fram...
WifiPsduMap m_psduMap
the A-MPDU being transmitted
void SendMultiStaBlockAck(const WifiTxParameters &txParams, Time durationId)
Send a Multi-STA Block Ack frame after the reception of some TB PPDUs.
static TypeId GetTypeId()
Get the type ID.
Time m_intraBssNavEnd
intra-BSS NAV expiration time
bool UlMuCsMediumIdle(const CtrlTriggerHeader &trigger) const
This method is intended to be called a SIFS after the reception of a Trigger Frame to determine wheth...
void UpdateNav(const WifiMacHeader &hdr, const WifiTxVector &txVector, const Time &surplus=Time{0}) override
Update the NAV, if needed, based on the Duration/ID of the given MAC header and the given surplus.
std::set< Mac48Address > GetTfRecipients(const CtrlTriggerHeader &trigger) const
Get the (link) address of the non-AP stations solicited by the given Trigger Frame.
void DoTbPpduTimeout(WifiPsduMap *psduMap, std::size_t nSolicitedStations, bool updateFailedCw)
Take the necessary actions after that some TB PPDUs are missing in response to Trigger Frame.
virtual std::optional< dBm_u > GetMostRecentRssi(const Mac48Address &address) const
Get the RSSI of the most recent packet received from the station having the given address.
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 ReceiveBasicTrigger(const CtrlTriggerHeader &trigger, const WifiMacHeader &hdr)
Take the necessary actions when receiving a Basic Trigger Frame.
WifiTxVector GetHeTbTxVector(CtrlTriggerHeader trigger, Mac48Address triggerSender) const
Return a TXVECTOR for the UL frame that the station will send in response to the given Trigger frame,...
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)
static std::pair< uint16_t, Time > ConvertHeTbPpduDurationToLSigLength(Time ppduDuration, const WifiTxVector &txVector, WifiPhyBand band)
Compute the L-SIG length value corresponding to the given HE TB PPDU duration.
Ptr< MpduAggregator > m_mpduAggregator
A-MPDU aggregator.
Ptr< BlockAckManager > GetBaManager(uint8_t tid) const
Get the Block Ack Manager handling the given TID.
virtual void BlockAckTimeout(Ptr< WifiPsdu > psdu, const WifiTxVector &txVector)
Called when the BlockAck timeout expires.
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 FinalizeMacHeader(Ptr< const WifiPsdu > psdu) override
Finalize the MAC header of the MPDUs in the given PSDU before transmission.
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...
virtual void NotifyTxToEdca(Ptr< const WifiPsdu > psdu) const
Notify the transmission of the given PSDU to the EDCAF associated with the AC the PSDU belongs to.
virtual void MissedBlockAck(Ptr< WifiPsdu > psdu, const WifiTxVector &txVector)
Take necessary actions when a BlockAck is missed, such as scheduling a BlockAckReq frame or the retra...
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 SendBlockAck(const RecipientBlockAckAgreement &agreement, Time durationId, WifiTxVector &blockAckTxVector, double rxSnr, std::optional< Mac48Address > gcrGroupAddr=std::nullopt)
Create a BlockAck frame with header equal to blockAck and start its transmission.
static Mac48Address GetBroadcast()
static uint32_t GetSizeIfAggregated(uint32_t mpduSize, uint32_t ampduSize)
Compute the size of the A-MPDU resulting from the aggregation of an MPDU of size mpduSize and an A-MP...
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.
static WifiMode GetOfdmRate6Mbps()
Return a WifiMode for OFDM at 6 Mbps.
Smart pointer class similar to boost::intrusive_ptr.
Ptr< QosTxop > m_edca
the EDCAF that gained channel access
std::optional< Mac48Address > m_txopHolder
MAC address of the TXOP holder.
void TransmissionFailed(bool forceCurrentCw=false) override
Take necessary actions upon a transmission failure.
virtual std::optional< Mac48Address > FindTxopHolder(const WifiMacHeader &hdr, const WifiTxVector &txVector)
Determine the holder of the TXOP, if possible, based on the received frame.
virtual bool SendCfEndIfNeeded()
Send a CF-End frame to indicate the completion of the TXOP, provided that the remaining duration is l...
virtual Ptr< WifiMpdu > CreateAliasIfNeeded(Ptr< WifiMpdu > mpdu) const
Create an alias of the given MPDU for transmission by this Frame Exchange Manager.
virtual bool IsWithinSizeAndTimeLimits(uint32_t ppduPayloadSize, Mac48Address receiver, const WifiTxParameters &txParams, Time ppduDurationLimit) const
Check whether the transmission time of the frame being built (as described by the given TX parameters...
Time m_singleExchangeProtectionSurplus
additional time to protect beyond end of the immediate frame exchange in case of non-zero TXOP limit ...
bool TryAddMpdu(Ptr< const WifiMpdu > mpdu, WifiTxParameters &txParams, Time availableTime) const
Recompute the protection and acknowledgment methods to use if the given MPDU is added to the frame be...
bool m_protectSingleExchange
true if the Duration/ID field in frames establishing protection only covers the immediate frame excha...
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.
static Time GetDelayLeft(const EventId &id)
Get the remaining time until this event will execute.
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.
a unique identifier for an interface.
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Ptr< WifiPsdu > GetWifiPsdu(Ptr< WifiMpdu > mpdu, const WifiTxVector &txVector) const override
Get a PSDU containing the given MPDU.
VhtFrameExchangeManager()
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
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
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.
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.
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_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Time Seconds(double value)
Construct a Time in the indicated unit.
AcIndex
This enumeration defines the Access Categories as an enumeration with values corresponding to the AC ...
@ WIFI_PHY_BAND_2_4GHZ
The 2.4 GHz band.
@ WIFI_MOD_CLASS_VHT
VHT (Clause 22)
@ WIFI_MOD_CLASS_HE
HE (Clause 27)
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.
Ptr< const AttributeChecker > MakeBooleanChecker()
uint32_t GetMuBarSize(TriggerFrameVariant variant, MHz_u bw, const std::list< BlockAckReqType > &types)
Return the total MU-BAR size (including FCS trailer).
U * PeekPointer(const Ptr< U > &p)
static constexpr uint16_t WIFI_MAC_FCS_LENGTH
The length in octets of the IEEE 802.11 MAC FCS field.
double MHz_u
MHz weak type.
bool IsTrigger(const WifiPsduMap &psduMap)
std::unordered_map< uint16_t, Ptr< WifiPsdu > > WifiPsduMap
Map of PSDUs indexed by STA-ID.
double dBm_u
dBm weak type
uint32_t GetBlockAckRequestSize(BlockAckReqType type)
Return the total BlockAckRequest 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.
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
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::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.