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());
647 auto hePhy = std::static_pointer_cast<HePhy>(
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 = std::static_pointer_cast<HePhy>(
896 m_phy->GetPhyEntity(responseTxVector->GetModulationClass()));
897 hePhy->SetTrigVector(m_trigVector, m_txTimer.GetDelayLeft());
899 else if (timerType == WifiTxTimer::NOT_RUNNING &&
900 (m_txParams.m_txVector.IsUlMu() ||
901 m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE))
905 Simulator::Schedule(txDuration, &WifiPsduMap::clear, &m_psduMap);
908 if (m_txTimer.IsRunning() && timerType != WifiTxTimer::WAIT_BLOCK_ACK_AFTER_TB_PPDU)
914 for (
const auto& address : staExpectResponseFrom)
916 if (!GetWifiRemoteStationManager()->GetEmlsrEnabled(address) ||
917 timerType == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF ||
918 m_protectedStas.contains(address))
920 m_sentFrameTo.insert(address);
935 auto sigBMode = hePhy->GetSigBMode(txVector);
939 for (
const auto& psdu : psduMap)
941 NS_LOG_DEBUG(
"Transmitting: [STAID=" << psdu.first <<
", " << *psdu.second <<
"]");
944 for (
const auto& [staId, psdu] : psduMap)
951 if (psduMap.size() > 1 || psduMap.begin()->second->IsAggregate() ||
952 psduMap.begin()->second->IsSingle())
958 SetTxNav(*psduMap.cbegin()->second->begin(), txDuration);
960 m_phy->Send(psduMap, txVector);
965 std::map<uint16_t, CtrlBAckRequestHeader> recipients)
const
978 for (
auto& userInfo : muBar)
980 auto recipientIt = recipients.find(userInfo.GetAid12());
981 NS_ASSERT(recipientIt != recipients.end());
984 userInfo.SetMuBarTriggerDepUserInfo(recipientIt->second);
988 bar->AddHeader(muBar);
1001 rxAddress =
m_apMac->GetStaList(
m_linkId).at(recipients.begin()->first);
1030 muRtsCtsProtection->muRts.begin()->GetAid12());
1034 muRtsCtsProtection->protectionTime =
1036 muRtsCtsProtection->muRtsTxVector,
1037 m_phy->GetPhyBand()) +
1039 2 *
m_phy->GetSifs();
1063 NS_ABORT_IF(dlMuBarBaAcknowledgment->stationsReplyingWithNormalAck.size() +
1064 dlMuBarBaAcknowledgment->stationsReplyingWithBlockAck.size() >
1067 if (!dlMuBarBaAcknowledgment->stationsReplyingWithNormalAck.empty())
1070 dlMuBarBaAcknowledgment->stationsReplyingWithNormalAck.begin()->second;
1076 if (!dlMuBarBaAcknowledgment->stationsReplyingWithBlockAck.empty())
1079 dlMuBarBaAcknowledgment->stationsReplyingWithBlockAck.begin()->second;
1082 info.blockAckTxVector,
1083 m_phy->GetPhyBand());
1086 for (
const auto& stations : dlMuBarBaAcknowledgment->stationsSendBlockAckReqTo)
1088 const auto& info = stations.second;
1089 duration +=
m_phy->GetSifs() +
1091 info.blockAckReqTxVector,
1092 m_phy->GetPhyBand()) +
1095 info.blockAckTxVector,
1096 m_phy->GetPhyBand());
1099 dlMuBarBaAcknowledgment->acknowledgmentTime = duration;
1106 auto dlMuTfMuBarAcknowledgment =
static_cast<WifiDlMuTfMuBar*
>(acknowledgment);
1110 for (
const auto& stations : dlMuTfMuBarAcknowledgment->stationsReplyingWithBlockAck)
1113 const auto& info = stations.second;
1114 NS_ASSERT(info.blockAckTxVector.GetHeMuUserInfoMap().size() == 1);
1115 uint16_t staId = info.blockAckTxVector.GetHeMuUserInfoMap().begin()->first;
1117 info.blockAckTxVector,
1118 m_phy->GetPhyBand(),
1121 if (currBlockAckDuration > duration)
1123 duration = currBlockAckDuration;
1129 WifiTxVector& txVector = dlMuTfMuBarAcknowledgment->stationsReplyingWithBlockAck.begin()
1130 ->second.blockAckTxVector;
1131 std::tie(dlMuTfMuBarAcknowledgment->ulLength, duration) =
1139 dlMuTfMuBarAcknowledgment->muBarTxVector.GetChannelWidth(),
1140 dlMuTfMuBarAcknowledgment->barTypes);
1141 if (dlMuTfMuBarAcknowledgment->muBarTxVector.GetModulationClass() >=
WIFI_MOD_CLASS_VHT)
1146 dlMuTfMuBarAcknowledgment->acknowledgmentTime =
1149 dlMuTfMuBarAcknowledgment->muBarTxVector,
1150 m_phy->GetPhyBand()) +
1151 m_phy->GetSifs() + duration;
1162 for (
const auto& stations : dlMuAggrTfAcknowledgment->stationsReplyingWithBlockAck)
1165 const auto& info = stations.second;
1166 NS_ASSERT(info.blockAckTxVector.GetHeMuUserInfoMap().size() == 1);
1167 uint16_t staId = info.blockAckTxVector.GetHeMuUserInfoMap().begin()->first;
1169 info.blockAckTxVector,
1170 m_phy->GetPhyBand(),
1173 if (currBlockAckDuration > duration)
1175 duration = currBlockAckDuration;
1182 dlMuAggrTfAcknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
1183 std::tie(dlMuAggrTfAcknowledgment->ulLength, duration) =
1185 dlMuAggrTfAcknowledgment->acknowledgmentTime =
m_phy->GetSifs() + duration;
1195 ulMuMultiStaBa->multiStaBaTxVector,
1196 m_phy->GetPhyBand());
1197 ulMuMultiStaBa->acknowledgmentTime =
m_phy->GetSifs() + duration;
1226 uint16_t staId)
const
1231 NS_ASSERT_MSG(userInfoIt != trigger.
end(),
"User Info field for AID=" << staId <<
" not found");
1234 if (uint8_t ru = userInfoIt->GetMuRtsRuAllocation(); ru < 65)
1258 txVector.SetChannelWidth(bw);
1281 NS_ASSERT_MSG(psduInfo,
"No information for " << receiver <<
" in TX params");
1282 NS_ASSERT_MSG(!psduInfo->seqNumbers.empty(),
"No sequence number for " << receiver);
1283 const auto tid = psduInfo->seqNumbers.cbegin()->first;
1291 {m_mac->GetBarTypeAsOriginator(receiver, tid)}),
1299 m_phy->GetPhyBand(),
1314 std::size_t nSolicitedStations,
1315 bool updateFailedCw)
1317 const auto& staMissedTbPpduFrom =
m_txTimer.GetStasExpectedToRespond();
1318 NS_LOG_FUNCTION(
this << psduMap << staMissedTbPpduFrom.size() << nSolicitedStations
1325 NS_ASSERT(!staMissedTbPpduFrom.empty());
1328 if (staMissedTbPpduFrom.size() == nSolicitedStations)
1332 psduMap->cbegin()->second->GetPayload(0)->PeekHeader(trigger);
1351 for (
const auto& address : staMissedTbPpduFrom)
1353 NS_LOG_DEBUG(address <<
" did not respond, hence it is no longer protected");
1369 std::size_t nSolicitedStations)
1379 const auto& staMissedBlockAckFrom =
m_txTimer.GetStasExpectedToRespond();
1380 NS_ASSERT(!staMissedBlockAckFrom.empty());
1382 if (staMissedBlockAckFrom.size() == nSolicitedStations)
1394 for (
const auto& sta : staMissedBlockAckFrom)
1403 if (staMissedBlockAckFrom.size() == nSolicitedStations)
1447 if (mpdu->IsQueued())
1449 m_mac->GetTxopQueue(mpdu->GetQueueAc())->GetOriginal(mpdu)->GetHeader().SetRetry();
1471 if (mpdu->IsQueued())
1473 mpdu->GetHeader().SetRetry();
1489 for (
const auto& userInfoField : trigger)
1492 userInfoField.GetAid12(),
1493 {userInfoField.GetRuAllocation(), userInfoField.GetUlMcs(), userInfoField.GetNss()});
1505 uint16_t staId =
m_staMac->GetAssociationId();
1512 NS_ASSERT_MSG(heConfiguration,
"This STA has to be an HE station to send an HE TB PPDU");
1515 if (userInfoIt->IsUlTargetRssiMaxTxPower())
1517 NS_LOG_LOGIC(
"AP requested using the max transmit power (" <<
m_phy->GetTxPowerEnd()
1547 auto reqTxPower =
dBm_u{
static_cast<double>(userInfoIt->GetUlTargetRssi() + pathLossDb)};
1550 uint8_t numPowerLevels =
m_phy->GetNTxPower();
1551 if (numPowerLevels > 1)
1553 dBm_u step = (
m_phy->GetTxPowerEnd() -
m_phy->GetTxPowerStart()) / (numPowerLevels - 1);
1554 powerLevel =
static_cast<uint8_t
>(
1555 ceil((reqTxPower -
m_phy->GetTxPowerStart()) /
1557 if (powerLevel > numPowerLevels)
1559 powerLevel = numPowerLevels;
1562 if (reqTxPower >
m_phy->GetPower(powerLevel))
1564 NS_LOG_WARN(
"The requested power level (" << reqTxPower <<
"dBm) cannot be satisfied (max: "
1565 <<
m_phy->GetTxPowerEnd() <<
"dBm)");
1569 <<
"{pathLoss=" << pathLossDb <<
"dB, reqTxPower=" << reqTxPower <<
"dBm}"
1571 <<
"{powerLevel=" << +powerLevel <<
" -> " <<
m_phy->GetPower(powerLevel) <<
"dBm}"
1572 <<
" PHY power capa "
1573 <<
"{min=" <<
m_phy->GetTxPowerStart() <<
"dBm, max=" <<
m_phy->GetTxPowerEnd()
1574 <<
"dBm, levels:" << +numPowerLevels <<
"}");
1593 for (
auto& userInfo : trigger)
1596 auto itAidAddr = staList.find(userInfo.GetAid12());
1600 auto rssi =
static_cast<int8_t>(*optRssi);
1601 rssi = (rssi >= -20)
1603 : ((rssi <= -110) ? -110 : rssi);
1604 userInfo.SetUlTargetRssi(rssi);
1613 auto txVectorCopy = txVector;
1615 if (psdu->GetNMpdus() == 1 && psdu->GetHeader(0).IsTrigger())
1618 psdu->GetPayload(0)->PeekHeader(trigger);
1662 NS_LOG_DEBUG(
"UL MU CS indicated medium busy, cannot send CTS");
1683 NS_ASSERT(!acknowledgment->stationsReceivingMultiStaBa.empty());
1686 blockAck.
SetType(acknowledgment->baType);
1690 for (
const auto& staInfo : acknowledgment->stationsReceivingMultiStaBa)
1692 receiver = staInfo.first.first;
1693 uint8_t tid = staInfo.first.second;
1694 std::size_t index = staInfo.second;
1702 NS_LOG_DEBUG(
"Multi-STA Block Ack: Sending All-ack to=" << receiver);
1707 if (acknowledgment->baType.m_bitmapLen.at(index) == 0)
1710 NS_LOG_DEBUG(
"Multi-STA Block Ack: Sending Ack to=" << receiver);
1718 auto agreement =
m_mac->GetBaAgreementEstablishedAsRecipient(receiver, tid);
1720 agreement->get().FillBlockAckBitmap(blockAck, index);
1721 NS_LOG_DEBUG(
"Multi-STA Block Ack: Sending Block Ack with seq="
1723 <<
" tid=" << +tid);
1729 hdr.
SetAddr1(acknowledgment->stationsReceivingMultiStaBa.size() == 1
1737 packet->AddHeader(blockAck);
1742 acknowledgment->multiStaBaTxVector,
1743 m_phy->GetPhyBand());
1755 const auto singleDurationId =
Max(durationId -
m_phy->GetSifs() - txDuration,
Seconds(0));
1758 psdu->SetDuration(singleDurationId);
1767 psdu->SetDuration(duration);
1770 psdu->GetPayload(0)->AddPacketTag(
m_muSnrTag);
1789 NS_LOG_DEBUG(
"Received a Trigger Frame (basic variant) soliciting a transmission");
1802 std::vector<uint8_t> tids;
1803 uint16_t staId =
m_staMac->GetAssociationId();
1806 for (uint8_t i = 0; i < 4; i++)
1809 tids.push_back(acIt->second.GetHighTid());
1810 tids.push_back(acIt->second.GetLowTid());
1824 m_phy->GetPhyBand());
1826 for (
const auto& tid : tids)
1830 if (!
m_mac->GetBaAgreementEstablishedAsOriginator(hdr.
GetAddr2(), tid))
1840 if (
auto mpdu =
GetBar(edca->GetAccessCategory(), tid, hdr.
GetAddr2());
1841 mpdu &&
TryAddMpdu(mpdu, txParams, ppduDuration))
1851 if (
auto mpdu = edca->PeekNextMpdu(
m_linkId, tid, receiver))
1854 if (
auto item = edca->GetNextMpdu(
m_linkId, mpdu, txParams, ppduDuration,
false))
1857 std::vector<Ptr<WifiMpdu>> mpduList =
1914 m_phy->GetPhyBand());
1917 std::vector<Ptr<WifiMpdu>> mpduList;
1919 for (uint8_t tid = 0; tid < 8; ++tid)
1921 if (!
m_mac->GetBaAgreementEstablishedAsOriginator(hdr.
GetAddr2(), tid))
1923 NS_LOG_DEBUG(
"Skipping tid=" << +tid <<
" because no agreement established");
1947 NS_LOG_DEBUG(
"Aggregating a QoS Null frame with tid=" << +tid);
1949 mpduList.push_back(mpdu);
1952 if (mpduList.empty())
1954 NS_LOG_DEBUG(
"Not enough time to send a QoS Null frame");
1960 uint16_t staId =
m_staMac->GetAssociationId();
1972 auto agreement =
m_mac->GetBaAgreementEstablishedAsRecipient(
m_bssid, tid);
1976 NS_LOG_DEBUG(
"There's not a valid agreement for this BlockAckReq");
2028 if (bssid != empty && bssid !=
m_bssid)
2036 if (bssid == empty && ta != empty && ra != empty && ta !=
m_bssid && ra !=
m_bssid)
2049 const auto bssColor =
m_mac->GetHeConfiguration()->m_bssColor;
2052 return bssColor != 0 && bssColor == txVector.
GetBssColor();
2058 const Time& surplus)
2079 NS_LOG_DEBUG(
"PPDU not classified as intra-BSS, update the basic NAV");
2084 NS_LOG_DEBUG(
"PPDU classified as intra-BSS, update the intra-BSS NAV");
2087 duration += surplus;
2095 NS_LOG_DEBUG(
"Received CF-End, resetting the intra-BSS NAV");
2122 auto navResetDelay =
2123 2 *
m_phy->GetSifs() +
2170std::optional<Mac48Address>
2183 return std::nullopt;
2218 "No User Info field for STA (" <<
m_self
2219 <<
") AID=" <<
m_staMac->GetAssociationId());
2221 std::set<uint8_t> indices;
2226 auto bw = ctsTxVector.GetChannelWidth();
2227 indices =
m_phy->GetOperatingChannel().GetAll20MHzChannelIndicesInPrimary(bw);
2232 m_phy->GetOperatingChannel().Get20MHzIndicesCoveringRu(userInfoIt->GetRuAllocation(),
2244 NS_LOG_FUNCTION(
this << *mpdu << rxSignalInfo << txVector << inAmpdu);
2247 NS_ASSERT(mpdu->GetHeader().GetAddr1().IsGroup() || mpdu->GetHeader().GetAddr1() ==
m_self);
2260 if (!
m_txTimer.GetStasExpectedToRespond().contains(sender))
2262 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2268 NS_LOG_DEBUG(
"Received a BlockAckReq in a TB PPDU from " << sender);
2271 mpdu->GetPacket()->PeekHeader(blockAckReq);
2275 m_mac->GetMldAddress(sender).value_or(sender),
2280 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, tid), index);
2281 acknowledgment->baType.m_bitmapLen.push_back(
2282 m_mac->GetBaTypeAsRecipient(sender, tid).m_bitmapLen.at(0));
2288 NS_LOG_DEBUG(
"Received an S-MPDU in a TB PPDU from " << sender <<
" (" << *mpdu <<
")");
2294 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, tid), index);
2295 acknowledgment->baType.m_bitmapLen.push_back(0);
2311 if (!acknowledgment->stationsReceivingMultiStaBa.empty() && !
m_multiStaBaEvent.IsPending())
2317 mpdu->GetHeader().GetDuration());
2323 if (
m_txTimer.GetStasExpectedToRespond().empty())
2347 const auto& sender = hdr.
GetAddr2();
2349 if (!
m_txTimer.GetStasExpectedToRespond().contains(sender))
2351 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2356 NS_LOG_WARN(
"No QoS Null frame in the received MPDU");
2360 NS_LOG_DEBUG(
"Received a QoS Null frame in a TB PPDU from " << sender);
2379 mpdu->GetPacket()->PeekPacketTag(tag);
2396 NS_LOG_DEBUG(
"Received a CTS frame in response to an MU-RTS");
2410 auto acknowledgment =
2412 NS_ASSERT(acknowledgment->stationsReplyingWithNormalAck.size() == 1);
2414 uint16_t staId =
m_apMac->GetAssociationId(
2415 acknowledgment->stationsReplyingWithNormalAck.begin()->first,
2420 acknowledgment->stationsReplyingWithNormalAck.begin()->first);
2422 mpdu->GetPacket()->PeekPacketTag(tag);
2440 NS_LOG_DEBUG(
"Received BlockAck in TB PPDU from=" << sender);
2443 mpdu->GetPacket()->PeekPacketTag(tag);
2447 mpdu->GetPacket()->PeekHeader(blockAck);
2449 std::pair<uint16_t, uint16_t> ret =
2452 m_mac->GetMldAddress(sender).value_or(sender),
2462 if (!
m_txTimer.GetStasExpectedToRespond().contains(sender))
2464 NS_LOG_WARN(
"Received a BlockAck from an unexpected stations: " << sender);
2470 if (
m_txTimer.GetStasExpectedToRespond().empty())
2490 mpdu->GetPacket()->PeekHeader(blockAck);
2493 "A Multi-STA BlockAck is expected after a TB PPDU");
2500 NS_LOG_DEBUG(
"The sender is not the AP we are associated with");
2504 uint16_t staId =
m_staMac->GetAssociationId();
2507 if (indices.empty())
2509 NS_LOG_DEBUG(
"No Per AID TID Info subfield intended for me");
2514 mpdu->GetPacket()->PeekPacketTag(tag);
2517 for (
const auto& index : indices)
2535 std::set<uint8_t> tids =
m_psduMap.at(staId)->GetTids();
2536 NS_ABORT_MSG_IF(tids.size() > 1,
"Multi-TID A-MPDUs not supported yet");
2537 tid = *tids.begin();
2540 std::pair<uint16_t, uint16_t> ret =
GetBaManager(tid)->NotifyGotBlockAck(
2554 if (
m_psduMap.at(staId)->GetHeader(0).IsQosData() &&
2556 || std::any_of(blockAck.
GetBitmap(index).begin(),
2558 [](uint8_t b) { return b != 0; })))
2574 for (
const auto& [staId, psdu] :
m_psduMap)
2576 if (psdu->GetNMpdus() == 1 && psdu->GetHeader(0).IsBlockAckReq())
2608 mpdu->GetPacket()->PeekHeader(trigger);
2619 uint16_t staId =
m_staMac->GetAssociationId();
2624 NS_LOG_DEBUG(
"Received MU-RTS Trigger Frame from=" << sender);
2645 NS_LOG_DEBUG(
"Received MU-BAR Trigger Frame from=" << sender);
2655 m_mac->GetMldAddress(sender).value_or(sender),
2675 else if (trigger.
IsBsrp())
2703 const std::vector<bool>& perMpduStatus)
2705 std::set<uint8_t> tids = psdu->GetTids();
2716 if (!
m_txTimer.GetStasExpectedToRespond().contains(sender))
2718 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2722 NS_LOG_DEBUG(
"Received an A-MPDU in a TB PPDU from " << sender <<
" (" << *psdu <<
")");
2724 if (std::any_of(tids.begin(), tids.end(), [&psdu](uint8_t tid) {
2725 return psdu->GetAckPolicyForTid(tid) == WifiMacHeader::NORMAL_ACK;
2728 if (std::all_of(perMpduStatus.cbegin(), perMpduStatus.cend(), [](
bool v) { return v; }))
2731 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, 14),
2733 acknowledgment->baType.m_bitmapLen.push_back(0);
2739 for (
const auto& tid : tids)
2741 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, tid),
2743 acknowledgment->baType.m_bitmapLen.push_back(
2744 m_mac->GetBaTypeAsRecipient(sender, tid).m_bitmapLen.at(0));
2752 if (!acknowledgment->stationsReceivingMultiStaBa.empty() && !
m_multiStaBaEvent.IsPending())
2758 psdu->GetDuration());
2764 if (
m_txTimer.GetStasExpectedToRespond().empty())
2789 if (!
m_txTimer.GetStasExpectedToRespond().contains(sender))
2791 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2794 if (std::none_of(psdu->begin(), psdu->end(), [](
Ptr<WifiMpdu> mpdu) {
2795 return mpdu->GetHeader().IsQosData() && !mpdu->GetHeader().HasData();
2798 NS_LOG_WARN(
"No QoS Null frame in the received PSDU");
2802 NS_LOG_DEBUG(
"Received QoS Null frames in a TB PPDU from " << sender);
2812 auto psduIt = psdu->begin();
2813 while (psduIt != psdu->end())
2815 if ((*psduIt)->GetHeader().IsTrigger())
2817 ReceiveMpdu(*psduIt, rxSignalInfo, txVector,
false);
2841 if (
m_txTimer.GetStasExpectedToRespond().empty())
AttributeValue implementation for Boolean.
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.
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.
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...
Ptr< const AttributeChecker > MakeBooleanChecker()
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
#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.
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).
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.
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).
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...
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.