26 #include "ns3/abort.h"
27 #include "ns3/ap-wifi-mac.h"
28 #include "ns3/erp-ofdm-phy.h"
30 #include "ns3/recipient-block-ack-agreement.h"
31 #include "ns3/snr-tag.h"
32 #include "ns3/sta-wifi-mac.h"
33 #include "ns3/wifi-mac-queue.h"
34 #include "ns3/wifi-mac-trailer.h"
39 #undef NS_LOG_APPEND_CONTEXT
40 #define NS_LOG_APPEND_CONTEXT std::clog << "[link=" << +m_linkId << "][mac=" << m_self << "] "
52 return psduMap.size() == 1 && psduMap.cbegin()->first ==
SU_STA_ID &&
53 psduMap.cbegin()->second->GetNMpdus() == 1 &&
54 psduMap.cbegin()->second->GetHeader(0).IsTrigger();
60 return psduMap.size() == 1 && psduMap.cbegin()->first ==
SU_STA_ID &&
61 psduMap.cbegin()->second->GetNMpdus() == 1 &&
62 psduMap.cbegin()->second->GetHeader(0).IsTrigger();
68 static TypeId tid =
TypeId(
"ns3::HeFrameExchangeManager")
70 .AddConstructor<HeFrameExchangeManager>()
71 .SetGroupName(
"Wifi");
76 : m_intraBssNavEnd(0),
77 m_triggerFrameInAmpdu(false)
135 "A Multi-User Scheduler can only be aggregated to an HE AP");
157 (mpdu->GetHeader().IsQosData() && !mpdu->GetHeader().GetAddr1().IsGroup() &&
159 mpdu->GetHeader().GetQosTid()))))
178 "The Multi-user Scheduler returned DL_MU_TX with empty psduMap, do not transmit");
189 auto packet = Create<Packet>();
229 <<
") incompatible with Basic Trigger Frame");
233 <<
") incompatible with BSRP Trigger Frame");
235 auto txVector = trigger.GetHeTbTxVector(trigger.begin()->GetAid12());
252 if (mpdu->IsQueued())
269 "Cannot use RTS/CTS with MU PPDUs");
294 for (
const auto& userInfo : protection->muRts)
296 const auto addressIt = aidAddrMap.find(userInfo.GetAid12());
297 NS_ASSERT_MSG(addressIt != aidAddrMap.end(),
"AID not found");
322 NS_LOG_FUNCTION(
this << muRtsSize << muRtsTxVector << txDuration << response);
357 protection->muRts.SetCsRequired(
true);
361 auto mpdu = Create<WifiMpdu>(payload, hdr);
364 mpdu->GetHeader().SetDuration(
366 protection->muRtsTxVector,
379 protection->muRtsTxVector,
391 protection->muRtsTxVector);
415 if (mpdu->IsQueued())
423 const auto& hdr =
m_psduMap.cbegin()->second->GetHeader(0);
424 if (!hdr.GetAddr1().IsGroup())
429 if (!hdr.GetAddr1().IsGroup() &&
454 for (
const auto& [staId, psdu] :
m_psduMap)
465 auto it = std::find_if(
468 [&to](std::pair<uint16_t,
Ptr<WifiPsdu>> psdu) { return psdu.second->GetAddr1() == to; });
469 if (it != psduMap.end())
524 std::set<Mac48Address> staExpectResponseFrom;
533 auto acknowledgment =
539 if (acknowledgment->stationsSendBlockAckReqTo.find(psdu.second->
GetAddr1()) !=
540 acknowledgment->stationsSendBlockAckReqTo.end())
543 std::set<uint8_t> tids = psdu.second->
GetTids();
545 "Acknowledgment method incompatible with a Multi-TID A-MPDU");
546 uint8_t tid = *tids.begin();
555 if (!acknowledgment->stationsReplyingWithNormalAck.empty())
560 &acknowledgment->stationsReplyingWithNormalAck.begin()->second.ackTxVector;
561 auto from = acknowledgment->stationsReplyingWithNormalAck.begin()->first;
564 mpdu = *psdu->
begin();
565 staExpectResponseFrom.insert(from);
567 else if (!acknowledgment->stationsReplyingWithBlockAck.empty())
572 &acknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
573 auto from = acknowledgment->stationsReplyingWithBlockAck.begin()->first;
575 staExpectResponseFrom.insert(from);
591 std::map<uint16_t, CtrlBAckRequestHeader> recipients;
593 NS_ASSERT(!acknowledgment->stationsReplyingWithBlockAck.empty());
594 auto staIt = acknowledgment->stationsReplyingWithBlockAck.begin();
596 while (staIt != acknowledgment->stationsReplyingWithBlockAck.end())
602 staIt->second.blockAckTxVector.GetHeMuUserInfo(staId));
603 recipients.emplace(staId, staIt->second.barHeader);
618 for (
auto& station : acknowledgment->stationsReplyingWithBlockAck)
620 staExpectResponseFrom.insert(station.first);
625 acknowledgment->muBarTxVector,
628 acknowledgment->acknowledgmentTime -= (
m_phy->
GetSifs() + txDuration);
632 &acknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
638 staExpectResponseFrom,
642 staExpectResponseFrom.size());
663 acknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
666 for (
auto& station : acknowledgment->stationsReplyingWithBlockAck)
668 staExpectResponseFrom.insert(station.first);
671 auto psduMapIt = std::find_if(
m_psduMap.begin(),
674 return psdu.second->GetAddr1() == station.first;
679 std::vector<Ptr<WifiMpdu>> mpduList(psduMapIt->second->begin(),
680 psduMapIt->second->end());
681 NS_ASSERT(mpduList.size() == psduMapIt->second->GetNMpdus());
684 station.second.blockAckTxVector.SetLength(acknowledgment->ulLength);
685 mpduList.push_back(
PrepareMuBar(station.second.blockAckTxVector,
686 {{psduMapIt->first, station.second.barHeader}}));
687 psduMapIt->second = Create<WifiPsdu>(std::move(mpduList));
690 station.second.blockAckTxVector.GetHeMuUserInfo(psduMapIt->first));
695 &acknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
705 mpdu = *m_psduMap.begin()->second->begin();
707 auto acknowledgment =
static_cast<WifiUlMuMultiStaBa*
>(m_txParams.m_acknowledgment.get());
710 for (
const auto& station : acknowledgment->stationsReceivingMultiStaBa)
712 staExpectResponseFrom.insert(station.first.first);
718 acknowledgment->baType.m_bitmapLen.clear();
721 responseTxVector = &acknowledgment->tbPpduTxVector;
722 m_trigVector = GetTrigVector(m_muScheduler->GetUlMuInfo(m_linkId).trigger);
728 !m_txParams.m_txVector.IsUlMu() &&
IsTrigger(m_psduMap))
730 CtrlTriggerHeader& trigger = m_muScheduler->GetUlMuInfo(m_linkId).trigger;
735 for (
const auto& userInfo : trigger)
737 auto staIt = m_apMac->GetStaList(m_linkId).find(userInfo.GetAid12());
738 NS_ASSERT(staIt != m_apMac->GetStaList(m_linkId).end());
739 staExpectResponseFrom.insert(staIt->second);
743 txVector = trigger.GetHeTbTxVector(trigger.begin()->GetAid12());
744 responseTxVector = &txVector;
745 m_trigVector = GetTrigVector(m_muScheduler->GetUlMuInfo(m_linkId).trigger);
750 else if (m_txParams.m_txVector.IsUlMu() &&
755 NS_ASSERT(m_staMac && m_staMac->IsAssociated());
756 auto recv = m_psduMap.begin()->second->GetAddr1();
757 txVector = GetWifiRemoteStationManager()->GetBlockAckTxVector(recv, m_txParams.m_txVector);
758 responseTxVector = &txVector;
759 staExpectResponseFrom.insert(recv);
764 else if (m_txParams.m_txVector.IsUlMu() &&
771 NS_ABORT_MSG(
"Unable to handle the selected acknowledgment method ("
772 << m_txParams.m_acknowledgment.get() <<
")");
777 for (
const auto& psdu : m_psduMap)
779 psduMap.emplace(psdu.first, psdu.second);
783 if (m_txParams.m_txVector.IsUlMu())
786 m_txParams.m_txVector,
787 m_phy->GetPhyBand());
792 m_phy->CalculateTxDuration(psduMap, m_txParams.m_txVector, m_phy->GetPhyBand());
795 Time durationId = GetPsduDurationId(txDuration, m_txParams);
796 for (
auto& psdu : m_psduMap)
798 psdu.second->SetDuration(durationId);
811 else if (!m_txParams.m_txVector.IsUlMu())
818 Time timeout = txDuration + m_phy->GetSifs() + m_phy->GetSlot() +
819 m_phy->CalculatePhyPreambleAndHeaderDuration(*responseTxVector);
820 m_channelAccessManager->NotifyAckTimeoutStartNow(
timeout);
827 m_txTimer.Set(timerType,
829 staExpectResponseFrom,
833 m_txParams.m_txVector);
837 m_txTimer.Set(timerType,
839 staExpectResponseFrom,
843 m_txParams.m_txVector);
846 m_txTimer.Set(timerType,
848 staExpectResponseFrom,
852 staExpectResponseFrom.size());
856 m_txTimer.Set(timerType,
858 staExpectResponseFrom,
862 staExpectResponseFrom.size());
865 m_txTimer.Set(timerType,
867 staExpectResponseFrom,
870 m_psduMap.begin()->second,
871 m_txParams.m_txVector);
880 ForwardPsduMapDown(psduMap, m_txParams.m_txVector);
887 auto hePhy = StaticCast<HePhy>(m_phy->GetPhyEntity(responseTxVector->GetModulationClass()));
888 hePhy->SetTrigVector(m_trigVector, m_txTimer.GetDelayLeft());
905 auto sigBMode = hePhy->GetSigBMode(txVector);
909 for (
const auto& psdu : psduMap)
911 NS_LOG_DEBUG(
"Transmitting: [STAID=" << psdu.first <<
", " << *psdu.second <<
"]");
914 for (
const auto& [staId, psdu] : psduMap)
916 FinalizeMacHeader(psdu);
917 NotifyTxToEdca(psdu);
921 if (psduMap.size() > 1 || psduMap.begin()->second->IsAggregate() ||
922 psduMap.begin()->second->IsSingle())
927 m_phy->Send(psduMap, txVector);
931 HeFrameExchangeManager::PrepareMuBar(
const WifiTxVector& responseTxVector,
932 std::map<uint16_t, CtrlBAckRequestHeader> recipients)
const
939 SetTargetRssi(muBar);
945 for (
auto& userInfo : muBar)
947 auto recipientIt = recipients.find(userInfo.GetAid12());
948 NS_ASSERT(recipientIt != recipients.end());
951 userInfo.SetMuBarTriggerDepUserInfo(recipientIt->second);
963 rxAddress = Mac48Address::GetBroadcast();
968 rxAddress = m_apMac->GetStaList(m_linkId).at(recipients.begin()->first);
980 return Create<WifiMpdu>(bar, hdr);
984 HeFrameExchangeManager::CalculateProtectionTime(
WifiProtection* protection)
const
989 if (protection->
method == WifiProtection::MU_RTS_CTS)
996 GetCtsTxVectorAfterMuRts(muRtsCtsProtection->muRts,
997 muRtsCtsProtection->muRts.begin()->GetAid12());
1001 muRtsCtsProtection->protectionTime =
1002 m_phy->CalculateTxDuration(muRtsSize,
1003 muRtsCtsProtection->muRtsTxVector,
1004 m_phy->GetPhyBand()) +
1005 m_phy->CalculateTxDuration(
GetCtsSize(), ctsTxVector, m_phy->GetPhyBand()) +
1006 2 * m_phy->GetSifs();
1010 VhtFrameExchangeManager::CalculateProtectionTime(protection);
1023 if (acknowledgment->
method == WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE)
1030 NS_ABORT_IF(dlMuBarBaAcknowledgment->stationsReplyingWithNormalAck.size() +
1031 dlMuBarBaAcknowledgment->stationsReplyingWithBlockAck.size() >
1034 if (!dlMuBarBaAcknowledgment->stationsReplyingWithNormalAck.empty())
1037 dlMuBarBaAcknowledgment->stationsReplyingWithNormalAck.begin()->second;
1040 m_phy->CalculateTxDuration(
GetAckSize(), info.ackTxVector, m_phy->GetPhyBand());
1043 if (!dlMuBarBaAcknowledgment->stationsReplyingWithBlockAck.empty())
1046 dlMuBarBaAcknowledgment->stationsReplyingWithBlockAck.begin()->second;
1047 duration += m_phy->GetSifs() + m_phy->CalculateTxDuration(
GetBlockAckSize(info.baType),
1048 info.blockAckTxVector,
1049 m_phy->GetPhyBand());
1052 for (
const auto& stations : dlMuBarBaAcknowledgment->stationsSendBlockAckReqTo)
1054 const auto& info = stations.second;
1055 duration += m_phy->GetSifs() +
1057 info.blockAckReqTxVector,
1058 m_phy->GetPhyBand()) +
1061 info.blockAckTxVector,
1062 m_phy->GetPhyBand());
1065 dlMuBarBaAcknowledgment->acknowledgmentTime = duration;
1070 else if (acknowledgment->
method == WifiAcknowledgment::DL_MU_TF_MU_BAR)
1072 auto dlMuTfMuBarAcknowledgment =
static_cast<WifiDlMuTfMuBar*
>(acknowledgment);
1076 for (
const auto& stations : dlMuTfMuBarAcknowledgment->stationsReplyingWithBlockAck)
1079 const auto& info = stations.second;
1080 NS_ASSERT(info.blockAckTxVector.GetHeMuUserInfoMap().size() == 1);
1081 uint16_t staId = info.blockAckTxVector.GetHeMuUserInfoMap().begin()->first;
1083 info.blockAckTxVector,
1084 m_phy->GetPhyBand(),
1087 if (currBlockAckDuration > duration)
1089 duration = currBlockAckDuration;
1095 WifiTxVector& txVector = dlMuTfMuBarAcknowledgment->stationsReplyingWithBlockAck.begin()
1096 ->second.blockAckTxVector;
1097 std::tie(dlMuTfMuBarAcknowledgment->ulLength, duration) =
1098 HePhy::ConvertHeTbPpduDurationToLSigLength(duration, txVector, m_phy->GetPhyBand());
1100 uint32_t muBarSize =
GetMuBarSize(dlMuTfMuBarAcknowledgment->barTypes);
1101 if (dlMuTfMuBarAcknowledgment->muBarTxVector.GetModulationClass() >=
WIFI_MOD_CLASS_VHT)
1104 muBarSize = MpduAggregator::GetSizeIfAggregated(muBarSize, 0);
1106 dlMuTfMuBarAcknowledgment->acknowledgmentTime =
1108 m_phy->CalculateTxDuration(muBarSize,
1109 dlMuTfMuBarAcknowledgment->muBarTxVector,
1110 m_phy->GetPhyBand()) +
1111 m_phy->GetSifs() + duration;
1116 else if (acknowledgment->
method == WifiAcknowledgment::DL_MU_AGGREGATE_TF)
1122 for (
const auto& stations : dlMuAggrTfAcknowledgment->stationsReplyingWithBlockAck)
1125 const auto& info = stations.second;
1126 NS_ASSERT(info.blockAckTxVector.GetHeMuUserInfoMap().size() == 1);
1127 uint16_t staId = info.blockAckTxVector.GetHeMuUserInfoMap().begin()->first;
1129 info.blockAckTxVector,
1130 m_phy->GetPhyBand(),
1133 if (currBlockAckDuration > duration)
1135 duration = currBlockAckDuration;
1142 dlMuAggrTfAcknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
1143 std::tie(dlMuAggrTfAcknowledgment->ulLength, duration) =
1144 HePhy::ConvertHeTbPpduDurationToLSigLength(duration, txVector, m_phy->GetPhyBand());
1145 dlMuAggrTfAcknowledgment->acknowledgmentTime = m_phy->GetSifs() + duration;
1150 else if (acknowledgment->
method == WifiAcknowledgment::UL_MU_MULTI_STA_BA)
1155 ulMuMultiStaBa->multiStaBaTxVector,
1156 m_phy->GetPhyBand());
1157 ulMuMultiStaBa->acknowledgmentTime = m_phy->GetSifs() + duration;
1162 else if (acknowledgment->
method == WifiAcknowledgment::ACK_AFTER_TB_PPDU)
1171 VhtFrameExchangeManager::CalculateAcknowledgmentTime(acknowledgment);
1176 HeFrameExchangeManager::GetCtsModeAfterMuRts()
const
1181 : OfdmPhy::GetOfdmRate6Mbps();
1186 uint16_t staId)
const
1191 NS_ASSERT_MSG(userInfoIt != trigger.
end(),
"User Info field for AID=" << staId <<
" not found");
1194 if (uint8_t ru = userInfoIt->GetMuRtsRuAllocation(); ru < 65)
1212 auto txVector = GetWifiRemoteStationManager()->GetCtsTxVector(m_bssid, GetCtsModeAfterMuRts());
1214 txVector.SetChannelWidth(bw);
1220 HeFrameExchangeManager::GetTxDuration(uint32_t ppduPayloadSize,
1226 return VhtFrameExchangeManager::GetTxDuration(ppduPayloadSize, receiver, txParams);
1233 txParams.
m_acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF)
1239 NS_ASSERT(info != acknowledgment->stationsReplyingWithBlockAck.end());
1242 MpduAggregator::GetSizeIfAggregated(info->second.muBarSize, ppduPayloadSize);
1245 uint16_t staId = (txParams.
m_txVector.
IsDlMu() ? m_apMac->GetAssociationId(receiver, m_linkId)
1246 : m_staMac->GetAssociationId());
1247 Time psduDuration = m_phy->CalculateTxDuration(ppduPayloadSize,
1249 m_phy->GetPhyBand(),
1256 HeFrameExchangeManager::TbPpduTimeout(
WifiPsduMap* psduMap, std::size_t nSolicitedStations)
1258 const auto& staMissedTbPpduFrom = m_txTimer.GetStasExpectedToRespond();
1259 NS_LOG_FUNCTION(
this << psduMap << staMissedTbPpduFrom.size() << nSolicitedStations);
1265 NS_ASSERT(!staMissedTbPpduFrom.empty());
1268 if (staMissedTbPpduFrom.size() == nSolicitedStations)
1271 m_edca->UpdateFailedCw(m_linkId);
1273 TransmissionFailed();
1275 else if (!m_multiStaBaEvent.IsRunning())
1277 m_edca->ResetCw(m_linkId);
1278 TransmissionSucceeded();
1285 HeFrameExchangeManager::BlockAcksInTbPpduTimeout(
WifiPsduMap* psduMap,
1286 std::size_t nSolicitedStations)
1291 NS_ASSERT(m_txParams.m_acknowledgment &&
1292 (m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF ||
1293 m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_TF_MU_BAR));
1296 const auto& staMissedBlockAckFrom = m_txTimer.GetStasExpectedToRespond();
1297 NS_ASSERT(!staMissedBlockAckFrom.empty());
1301 if (staMissedBlockAckFrom.size() == nSolicitedStations)
1305 GetWifiRemoteStationManager()->ReportDataFailed(*psduMap->begin()->second->begin());
1317 m_triggerFrame =
nullptr;
1320 for (
const auto& sta : staMissedBlockAckFrom)
1329 MissedBlockAck(psdu, m_txParams.m_txVector, psduResetCw);
1330 resetCw = resetCw || psduResetCw;
1337 m_edca->ResetCw(m_linkId);
1341 m_edca->UpdateFailedCw(m_linkId);
1344 if (staMissedBlockAckFrom.size() == nSolicitedStations)
1347 TransmissionFailed();
1351 TransmissionSucceeded();
1364 GetWifiRemoteStationManager()->ReportDataFailed(*psdu->
begin());
1366 MissedBlockAck(psdu, m_txParams.m_txVector, resetCw);
1381 VhtFrameExchangeManager::NormalAckTimeout(mpdu, txVector);
1386 for (
auto& psdu : m_psduMap)
1390 if (mpdu->IsQueued())
1392 m_mac->GetTxopQueue(mpdu->GetQueueAc())->GetOriginal(mpdu)->GetHeader().SetRetry();
1393 mpdu->ResetInFlight(m_linkId);
1405 VhtFrameExchangeManager::BlockAckTimeout(psdu, txVector);
1410 for (
auto& psdu : m_psduMap)
1414 if (mpdu->IsQueued())
1416 mpdu->GetHeader().SetRetry();
1432 for (
const auto& userInfoField : trigger)
1435 userInfoField.GetAid12(),
1436 {userInfoField.GetRuAllocation(), userInfoField.GetUlMcs(), userInfoField.GetNss()});
1448 uint16_t staId = m_staMac->GetAssociationId();
1455 NS_ASSERT_MSG(heConfiguration,
"This STA has to be an HE station to send an HE TB PPDU");
1458 if (userInfoIt->IsUlTargetRssiMaxTxPower())
1460 NS_LOG_LOGIC(
"AP requested using the max transmit power (" << m_phy->GetTxPowerEnd()
1466 uint8_t powerLevel = GetWifiRemoteStationManager()->GetDefaultTxPowerLevel();
1484 auto optRssi = GetMostRecentRssi(triggerSender);
1488 static_cast<int8_t
>(
1490 auto reqTxPowerDbm =
static_cast<double>(userInfoIt->GetUlTargetRssi() + pathLossDb);
1493 uint8_t numPowerLevels = m_phy->GetNTxPower();
1494 if (numPowerLevels > 1)
1496 double stepDbm = (m_phy->GetTxPowerEnd() - m_phy->GetTxPowerStart()) / (numPowerLevels - 1);
1497 powerLevel =
static_cast<uint8_t
>(
1498 ceil((reqTxPowerDbm - m_phy->GetTxPowerStart()) /
1500 if (powerLevel > numPowerLevels)
1502 powerLevel = numPowerLevels;
1505 if (reqTxPowerDbm > m_phy->GetPowerDbm(powerLevel))
1508 << reqTxPowerDbm <<
"dBm) cannot be satisfied (max: " << m_phy->GetTxPowerEnd()
1513 <<
"input {pathLoss=" << pathLossDb <<
"dB, reqTxPower=" << reqTxPowerDbm <<
"dBm}"
1514 <<
" output {powerLevel=" << +powerLevel <<
" -> "
1515 << m_phy->GetPowerDbm(powerLevel) <<
"dBm}"
1516 <<
" PHY power capa {min=" << m_phy->GetTxPowerStart() <<
"dBm, max="
1517 << m_phy->GetTxPowerEnd() <<
"dBm, levels:" << +numPowerLevels <<
"}");
1522 std::optional<double>
1525 return GetWifiRemoteStationManager()->GetMostRecentRssi(
address);
1535 m_phy->GetPowerDbm(GetWifiRemoteStationManager()->GetDefaultTxPowerLevel())));
1536 for (
auto& userInfo : trigger)
1538 const auto staList = m_apMac->GetStaList(m_linkId);
1539 auto itAidAddr = staList.find(userInfo.GetAid12());
1541 auto optRssi = GetMostRecentRssi(itAidAddr->second);
1543 auto rssi =
static_cast<int8_t
>(*optRssi);
1544 rssi = (rssi >= -20)
1546 : ((rssi <= -110) ? -110 : rssi);
1547 userInfo.SetUlTargetRssi(rssi);
1556 auto txVectorCopy = txVector;
1575 if (m_staMac !=
nullptr && m_staMac->IsAssociated() &&
1586 psdu = Create<const WifiPsdu>(Create<Packet>(), rts);
1590 GetWifiRemoteStationManager()->GetCtsTxVector(m_bssid, GetCtsModeAfterMuRts());
1593 VhtFrameExchangeManager::PostProcessFrame(psdu, txVectorCopy);
1603 if (!UlMuCsMediumIdle(trigger))
1605 NS_LOG_DEBUG(
"UL MU CS indicated medium busy, cannot send CTS");
1609 NS_ASSERT(m_staMac !=
nullptr && m_staMac->IsAssociated());
1610 WifiTxVector ctsTxVector = GetCtsTxVectorAfterMuRts(trigger, m_staMac->GetAssociationId());
1613 DoSendCtsAfterRts(muRtsHdr, ctsTxVector, muRtsSnr);
1623 txParams.
m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
1626 NS_ASSERT(!acknowledgment->stationsReceivingMultiStaBa.empty());
1629 blockAck.
SetType(acknowledgment->baType);
1633 for (
const auto& staInfo : acknowledgment->stationsReceivingMultiStaBa)
1635 receiver = staInfo.first.first;
1636 uint8_t tid = staInfo.first.second;
1637 std::size_t index = staInfo.second;
1639 blockAck.
SetAid11(m_apMac->GetAssociationId(receiver, m_linkId), index);
1645 NS_LOG_DEBUG(
"Multi-STA Block Ack: Sending All-ack to=" << receiver);
1650 if (acknowledgment->baType.m_bitmapLen.at(index) == 0)
1653 NS_LOG_DEBUG(
"Multi-STA Block Ack: Sending Ack to=" << receiver);
1661 auto agreement = m_mac->GetBaAgreementEstablishedAsRecipient(receiver, tid);
1663 agreement->get().FillBlockAckBitmap(&blockAck, index);
1664 NS_LOG_DEBUG(
"Multi-STA Block Ack: Sending Block Ack with seq="
1666 <<
" tid=" << +tid);
1672 hdr.
SetAddr1(acknowledgment->stationsReceivingMultiStaBa.size() == 1
1674 : Mac48Address::GetBroadcast());
1682 GetWifiPsdu(Create<WifiMpdu>(packet, hdr), acknowledgment->multiStaBaTxVector);
1685 acknowledgment->multiStaBaTxVector,
1686 m_phy->GetPhyBand());
1698 if (m_edca->GetTxopLimit(m_linkId).IsZero())
1711 ForwardPsduDown(psdu, acknowledgment->multiStaBaTxVector);
1715 m_edca->ResetCw(m_linkId);
1717 Simulator::Schedule(txDuration, &HeFrameExchangeManager::TransmissionSucceeded,
this);
1726 NS_ASSERT(m_staMac && m_staMac->IsAssociated());
1728 NS_LOG_DEBUG(
"Received a Trigger Frame (basic variant) soliciting a transmission");
1730 if (!UlMuCsMediumIdle(trigger))
1741 std::vector<uint8_t> tids;
1742 uint16_t staId = m_staMac->GetAssociationId();
1745 for (uint8_t i = 0; i < 4; i++)
1748 tids.push_back(acIt->second.GetHighTid());
1749 tids.push_back(acIt->second.GetLowTid());
1761 Time ppduDuration = HePhy::ConvertLSigLengthToHeTbPpduDuration(trigger.
GetUlLength(),
1763 m_phy->GetPhyBand());
1765 for (
const auto& tid : tids)
1769 if (!m_mac->GetBaAgreementEstablishedAsOriginator(hdr.
GetAddr2(), tid))
1780 mpdu && TryAddMpdu(mpdu, txParams, ppduDuration))
1783 psdu = Create<WifiPsdu>(mpdu,
true);
1789 GetWifiRemoteStationManager()->GetMldAddress(hdr.
GetAddr2()).value_or(hdr.
GetAddr2());
1790 if (
auto mpdu = edca->
PeekNextMpdu(m_linkId, tid, receiver))
1792 mpdu = CreateAliasIfNeeded(mpdu);
1793 if (
auto item = edca->
GetNextMpdu(m_linkId, mpdu, txParams, ppduDuration,
false))
1796 std::vector<Ptr<WifiMpdu>> mpduList =
1797 m_mpduAggregator->GetNextAmpdu(item, txParams, ppduDuration);
1798 psdu = (mpduList.size() > 1 ? Create<WifiPsdu>(std::move(mpduList))
1799 : Create<WifiPsdu>(item,
true));
1808 SendPsduMapWithProtection(
WifiPsduMap{{staId, psdu}}, txParams);
1813 SendQosNullFramesInTbPpdu(trigger, hdr);
1823 NS_ASSERT(m_staMac && m_staMac->IsAssociated());
1827 if (!UlMuCsMediumIdle(trigger))
1850 Time ppduDuration = HePhy::ConvertLSigLengthToHeTbPpduDuration(trigger.
GetUlLength(),
1852 m_phy->GetPhyBand());
1856 std::vector<Ptr<WifiMpdu>> mpduList;
1861 IsWithinSizeAndTimeLimits(
1862 txParams.
GetSizeIfAddMpdu(mpdu = Create<WifiMpdu>(Create<Packet>(), header)),
1867 if (!m_mac->GetBaAgreementEstablishedAsOriginator(hdr.
GetAddr2(), tid))
1869 NS_LOG_DEBUG(
"Skipping tid=" << +tid <<
" because no agreement established");
1874 NS_LOG_DEBUG(
"Aggregating a QoS Null frame with tid=" << +tid);
1882 UpdateTxDuration(mpdu->GetHeader().GetAddr1(), txParams);
1883 mpduList.push_back(mpdu);
1887 if (mpduList.empty())
1889 NS_LOG_DEBUG(
"Not enough time to send a QoS Null frame");
1893 Ptr<WifiPsdu> psdu = (mpduList.size() > 1 ? Create<WifiPsdu>(std::move(mpduList))
1894 : Create<WifiPsdu>(mpduList.front(),
true));
1895 uint16_t staId = m_staMac->GetAssociationId();
1896 SendPsduMapWithProtection(
WifiPsduMap{{staId, psdu}}, txParams);
1907 auto agreement = m_mac->GetBaAgreementEstablishedAsRecipient(m_bssid, tid);
1911 NS_LOG_DEBUG(
"There's not a valid agreement for this BlockAckReq");
1915 if (!UlMuCsMediumIdle(trigger))
1921 auto txVector = GetHeTbTxVector(trigger, m_bssid);
1922 SendBlockAck(*agreement, durationId, txVector, snr);
1941 if (ra == m_bssid || ta == m_bssid || bssid == m_bssid)
1949 if (psdu->
GetHeader(0).
IsCtl() && ta == empty && ra == m_txopHolder)
1963 if (bssid != empty && bssid != m_bssid)
1971 if (bssid == empty && ta != empty && ra != empty && ta != m_bssid && ra != m_bssid)
1984 const auto bssColor = m_mac->GetHeConfiguration()->GetBssColor();
1987 return bssColor != 0 && bssColor == txVector.
GetBssColor();
2010 if (!IsIntraBssPpdu(psdu, txVector))
2012 NS_LOG_DEBUG(
"PPDU not classified as intra-BSS, update the basic NAV");
2013 VhtFrameExchangeManager::UpdateNav(psdu, txVector);
2017 NS_LOG_DEBUG(
"PPDU classified as intra-BSS, update the intra-BSS NAV");
2027 NS_LOG_DEBUG(
"Received CF-End, resetting the intra-BSS NAV");
2028 IntraBssNavResetTimeout();
2035 if (intraBssNavEnd > m_intraBssNavEnd)
2037 m_intraBssNavEnd = intraBssNavEnd;
2038 NS_LOG_DEBUG(
"Updated intra-BSS NAV=" << m_intraBssNavEnd);
2052 GetWifiRemoteStationManager()->GetCtsTxVector(psdu->
GetAddr2(), txVector.
GetMode());
2053 auto navResetDelay =
2054 2 * m_phy->GetSifs() +
2055 WifiPhy::CalculateTxDuration(
GetCtsSize(), ctsTxVector, m_phy->GetPhyBand()) +
2056 m_phy->CalculatePhyPreambleAndHeaderDuration(ctsTxVector) + 2 * m_phy->GetSlot();
2057 m_intraBssNavResetEvent =
2058 Simulator::Schedule(navResetDelay,
2059 &HeFrameExchangeManager::IntraBssNavResetTimeout,
2063 NS_LOG_DEBUG(
"Current intra-BSS NAV=" << m_intraBssNavEnd);
2065 m_channelAccessManager->NotifyNavStartNow(duration);
2069 HeFrameExchangeManager::ClearTxopHolderIfNeeded()
2074 m_txopHolder.reset();
2079 HeFrameExchangeManager::NavResetTimeout()
2085 Time intraBssNav = Simulator::GetDelayLeft(m_intraBssNavResetEvent);
2086 m_channelAccessManager->NotifyNavResetNow(intraBssNav);
2090 HeFrameExchangeManager::IntraBssNavResetTimeout()
2094 ClearTxopHolderIfNeeded();
2096 Time basicNav = Simulator::GetDelayLeft(m_navResetEvent);
2097 m_channelAccessManager->NotifyNavResetNow(basicNav);
2107 m_txopHolder = m_bssid;
2109 else if (!txVector.
IsUlMu())
2111 VhtFrameExchangeManager::SetTxopHolder(psdu, txVector);
2116 HeFrameExchangeManager::VirtualCsMediumIdle()
const
2144 NS_ASSERT_MSG(m_staMac,
"UL MU CS is only performed by non-AP STAs");
2147 "No User Info field for STA (" << m_self
2148 <<
") AID=" << m_staMac->GetAssociationId());
2150 std::set<uint8_t> indices;
2154 auto ctsTxVector = GetCtsTxVectorAfterMuRts(trigger, m_staMac->GetAssociationId());
2155 auto bw = ctsTxVector.GetChannelWidth();
2156 indices = m_phy->GetOperatingChannel().GetAll20MHzChannelIndicesInPrimary(bw);
2161 m_phy->GetOperatingChannel().Get20MHzIndicesCoveringRu(userInfoIt->GetRuAllocation(),
2164 return !m_channelAccessManager->GetPer20MHzBusy(indices);
2174 NS_ASSERT(mpdu->GetHeader().GetAddr1().IsGroup() || mpdu->GetHeader().GetAddr1() == m_self);
2178 if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
2179 m_txTimer.GetReason() == WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF)
2182 NS_ASSERT(m_txParams.m_acknowledgment &&
2183 m_txParams.m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
2184 auto acknowledgment =
static_cast<WifiUlMuMultiStaBa*
>(m_txParams.m_acknowledgment.get());
2187 if (m_txTimer.GetStasExpectedToRespond().count(sender) == 0)
2189 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2195 NS_LOG_DEBUG(
"Received a BlockAckReq in a TB PPDU from " << sender);
2198 mpdu->GetPacket()->PeekHeader(blockAckReq);
2201 GetBaManager(tid)->NotifyGotBlockAckRequest(
2202 m_mac->GetMldAddress(sender).value_or(sender),
2207 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, tid), index);
2208 acknowledgment->baType.m_bitmapLen.push_back(
2209 m_mac->GetBaTypeAsRecipient(sender, tid).m_bitmapLen.at(0));
2211 m_muSnrTag.Set(staId, rxSignalInfo.
snr);
2215 NS_LOG_DEBUG(
"Received an S-MPDU in a TB PPDU from " << sender <<
" (" << *mpdu <<
")");
2218 GetBaManager(tid)->NotifyGotMpdu(mpdu);
2221 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, tid), index);
2222 acknowledgment->baType.m_bitmapLen.push_back(0);
2224 m_muSnrTag.Set(staId, rxSignalInfo.
snr);
2233 VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
2238 if (!acknowledgment->stationsReceivingMultiStaBa.empty() && !m_multiStaBaEvent.IsRunning())
2240 m_multiStaBaEvent = Simulator::Schedule(m_phy->GetSifs(),
2241 &HeFrameExchangeManager::SendMultiStaBlockAck,
2243 std::cref(m_txParams),
2244 mpdu->GetHeader().GetDuration());
2248 m_txTimer.GotResponseFrom(sender);
2250 if (m_txTimer.GetStasExpectedToRespond().empty())
2254 m_channelAccessManager->NotifyAckTimeoutResetNow();
2256 if (!m_multiStaBaEvent.IsRunning())
2261 m_edca->ResetCw(m_linkId);
2262 TransmissionSucceeded();
2270 if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
2271 m_txTimer.GetReason() == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF &&
2274 const auto& sender = hdr.
GetAddr2();
2276 if (m_txTimer.GetStasExpectedToRespond().count(sender) == 0)
2278 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2283 NS_LOG_WARN(
"No QoS Null frame in the received MPDU");
2287 NS_LOG_DEBUG(
"Received a QoS Null frame in a TB PPDU from " << sender);
2290 m_txTimer.GotResponseFrom(sender);
2292 if (m_txTimer.GetStasExpectedToRespond().empty())
2296 m_channelAccessManager->NotifyAckTimeoutResetNow();
2300 m_edca->ResetCw(m_linkId);
2301 TransmissionSucceeded();
2310 if (hdr.
IsCts() && m_txTimer.IsRunning() &&
2311 m_txTimer.GetReason() == WifiTxTimer::WAIT_CTS && m_psduMap.size() == 1)
2316 Mac48Address sender = m_psduMap.begin()->second->GetAddr1();
2320 mpdu->GetPacket()->PeekPacketTag(tag);
2321 GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
2322 GetWifiRemoteStationManager()->ReportRtsOk(m_psduMap.begin()->second->GetHeader(0),
2328 m_channelAccessManager->NotifyCtsTimeoutResetNow();
2329 Simulator::Schedule(m_phy->GetSifs(),
2330 &HeFrameExchangeManager::ProtectionCompleted,
2333 else if (hdr.
IsCts() && m_txTimer.IsRunning() &&
2334 m_txTimer.GetReason() == WifiTxTimer::WAIT_CTS_AFTER_MU_RTS)
2339 NS_LOG_DEBUG(
"Received a CTS frame in response to an MU-RTS");
2342 m_channelAccessManager->NotifyCtsTimeoutResetNow();
2343 Simulator::Schedule(m_phy->GetSifs(),
2344 &HeFrameExchangeManager::ProtectionCompleted,
2347 else if (hdr.
IsAck() && m_txTimer.IsRunning() &&
2348 m_txTimer.GetReason() == WifiTxTimer::WAIT_NORMAL_ACK_AFTER_DL_MU_PPDU)
2352 NS_ASSERT(m_txParams.m_acknowledgment->method ==
2353 WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE);
2355 auto acknowledgment =
2357 NS_ASSERT(acknowledgment->stationsReplyingWithNormalAck.size() == 1);
2359 uint16_t staId = m_apMac->GetAssociationId(
2360 acknowledgment->stationsReplyingWithNormalAck.begin()->first,
2362 auto it = m_psduMap.find(staId);
2365 acknowledgment->stationsReplyingWithNormalAck.begin()->first);
2367 mpdu->GetPacket()->PeekPacketTag(tag);
2368 ReceivedNormalAck(*it->second->begin(),
2369 m_txParams.m_txVector,
2382 m_txTimer.GetReason() == WifiTxTimer::WAIT_BLOCK_ACKS_IN_TB_PPDU)
2385 NS_LOG_DEBUG(
"Received BlockAck in TB PPDU from=" << sender);
2388 mpdu->GetPacket()->PeekPacketTag(tag);
2392 mpdu->GetPacket()->PeekHeader(blockAck);
2394 std::pair<uint16_t, uint16_t> ret =
2395 GetBaManager(tid)->NotifyGotBlockAck(m_linkId,
2397 m_mac->GetMldAddress(sender).value_or(sender),
2399 GetWifiRemoteStationManager()->ReportAmpduTxStatus(sender,
2404 m_txParams.m_txVector);
2407 if (m_txTimer.GetStasExpectedToRespond().count(sender) == 0)
2409 NS_LOG_WARN(
"Received a BlockAck from an unexpected stations: " << sender);
2413 m_txTimer.GotResponseFrom(sender);
2415 if (m_txTimer.GetStasExpectedToRespond().empty())
2419 m_channelAccessManager->NotifyAckTimeoutResetNow();
2423 m_triggerFrame =
nullptr;
2426 m_edca->ResetCw(m_linkId);
2428 TransmissionSucceeded();
2431 else if (hdr.
IsBlockAck() && m_txTimer.IsRunning() &&
2432 m_txTimer.GetReason() == WifiTxTimer::WAIT_BLOCK_ACK_AFTER_TB_PPDU)
2435 mpdu->GetPacket()->PeekHeader(blockAck);
2438 "A Multi-STA BlockAck is expected after a TB PPDU");
2441 NS_ASSERT(m_staMac && m_staMac->IsAssociated());
2444 NS_LOG_DEBUG(
"The sender is not the AP we are associated with");
2448 uint16_t staId = m_staMac->GetAssociationId();
2451 if (indices.empty())
2453 NS_LOG_DEBUG(
"No Per AID TID Info subfield intended for me");
2458 mpdu->GetPacket()->PeekPacketTag(tag);
2461 for (
const auto& index : indices)
2468 NS_ABORT_IF(m_psduMap.empty() || m_psduMap.begin()->first != staId);
2469 GetBaManager(tid)->NotifyGotAck(m_linkId, *m_psduMap.at(staId)->begin());
2478 NS_ABORT_IF(m_psduMap.empty() || m_psduMap.begin()->first != staId);
2479 std::set<uint8_t> tids = m_psduMap.at(staId)->GetTids();
2480 NS_ABORT_MSG_IF(tids.size() > 1,
"Multi-TID A-MPDUs not supported yet");
2481 tid = *tids.begin();
2484 std::pair<uint16_t, uint16_t> ret = GetBaManager(tid)->NotifyGotBlockAck(
2490 GetWifiRemoteStationManager()->ReportAmpduTxStatus(hdr.
GetAddr2(),
2495 m_txParams.m_txVector);
2498 if (m_psduMap.at(staId)->GetHeader(0).IsQosData() &&
2500 || std::any_of(blockAck.
GetBitmap(index).begin(),
2502 [](uint8_t b) { return b != 0; })))
2504 NS_ASSERT(m_psduMap.at(staId)->GetHeader(0).HasData());
2505 NS_ASSERT(m_psduMap.at(staId)->GetHeader(0).GetQosTid() == tid);
2510 m_mac->GetQosTxop(tid)->StartMuEdcaTimerNow(m_linkId);
2516 m_channelAccessManager->NotifyAckTimeoutResetNow();
2518 for (
const auto& [staId, psdu] : m_psduMap)
2520 if (psdu->GetNMpdus() == 1 && psdu->GetHeader(0).IsBlockAckReq())
2527 else if (hdr.
IsBlockAck() && m_txTimer.IsRunning() &&
2528 m_txTimer.GetReason() == WifiTxTimer::WAIT_BLOCK_ACK)
2534 VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
2547 m_triggerFrameInAmpdu =
true;
2552 mpdu->GetPacket()->PeekHeader(trigger);
2563 uint16_t staId = m_staMac->GetAssociationId();
2568 NS_LOG_DEBUG(
"Received MU-RTS Trigger Frame from=" << sender);
2569 GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
2579 Simulator::Schedule(m_phy->GetSifs(),
2580 &HeFrameExchangeManager::SendCtsAfterMuRts,
2589 NS_LOG_DEBUG(
"Received MU-BAR Trigger Frame from=" << sender);
2590 GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
2598 GetBaManager(tid)->NotifyGotBlockAckRequest(
2599 m_mac->GetMldAddress(sender).value_or(sender),
2603 Simulator::Schedule(m_phy->GetSifs(),
2604 &HeFrameExchangeManager::ReceiveMuBarTrigger,
2613 Simulator::Schedule(m_phy->GetSifs(),
2614 &HeFrameExchangeManager::ReceiveBasicTrigger,
2619 else if (trigger.
IsBsrp())
2621 Simulator::Schedule(m_phy->GetSifs(),
2622 &HeFrameExchangeManager::SendQosNullFramesInTbPpdu,
2631 VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
2639 VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
2647 const std::vector<bool>& perMpduStatus)
2649 std::set<uint8_t> tids = psdu->
GetTids();
2651 if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
2652 m_txTimer.GetReason() == WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF)
2655 NS_ASSERT(m_txParams.m_acknowledgment &&
2656 m_txParams.m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
2657 auto acknowledgment =
static_cast<WifiUlMuMultiStaBa*
>(m_txParams.m_acknowledgment.get());
2660 if (m_txTimer.GetStasExpectedToRespond().count(sender) == 0)
2662 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2666 NS_LOG_DEBUG(
"Received an A-MPDU in a TB PPDU from " << sender <<
" (" << *psdu <<
")");
2668 if (std::any_of(tids.begin(), tids.end(), [&psdu](uint8_t tid) {
2669 return psdu->GetAckPolicyForTid(tid) == WifiMacHeader::NORMAL_ACK;
2672 if (std::all_of(perMpduStatus.cbegin(), perMpduStatus.cend(), [](
bool v) { return v; }))
2675 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, 14),
2677 acknowledgment->baType.m_bitmapLen.push_back(0);
2683 for (
const auto& tid : tids)
2685 acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, tid),
2687 acknowledgment->baType.m_bitmapLen.push_back(
2688 m_mac->GetBaTypeAsRecipient(sender, tid).m_bitmapLen.at(0));
2692 m_muSnrTag.Set(staId, rxSignalInfo.
snr);
2696 if (!acknowledgment->stationsReceivingMultiStaBa.empty() && !m_multiStaBaEvent.IsRunning())
2698 m_multiStaBaEvent = Simulator::Schedule(m_phy->GetSifs(),
2699 &HeFrameExchangeManager::SendMultiStaBlockAck,
2701 std::cref(m_txParams),
2706 m_txTimer.GotResponseFrom(sender);
2708 if (m_txTimer.GetStasExpectedToRespond().empty())
2712 m_channelAccessManager->NotifyAckTimeoutResetNow();
2714 if (!m_multiStaBaEvent.IsRunning())
2719 m_edca->ResetCw(m_linkId);
2720 TransmissionSucceeded();
2728 if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
2729 m_txTimer.GetReason() == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF)
2733 if (m_txTimer.GetStasExpectedToRespond().count(sender) == 0)
2735 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2739 return mpdu->GetHeader().IsQosData() && !mpdu->GetHeader().HasData();
2742 NS_LOG_WARN(
"No QoS Null frame in the received PSDU");
2746 NS_LOG_DEBUG(
"Received QoS Null frames in a TB PPDU from " << sender);
2749 m_txTimer.GotResponseFrom(sender);
2751 if (m_txTimer.GetStasExpectedToRespond().empty())
2755 m_channelAccessManager->NotifyAckTimeoutResetNow();
2759 m_edca->ResetCw(m_linkId);
2760 TransmissionSucceeded();
2767 if (m_triggerFrameInAmpdu)
2770 auto psduIt = psdu->
begin();
2771 while (psduIt != psdu->
end())
2773 if ((*psduIt)->GetHeader().IsTrigger())
2775 ReceiveMpdu(*psduIt, rxSignalInfo, txVector,
false);
2780 m_triggerFrameInAmpdu =
false;
2785 VhtFrameExchangeManager::EndReceiveAmpdu(psdu, rxSignalInfo, txVector, perMpduStatus);
uint16_t GetAssociationId(Mac48Address addr, uint8_t linkId) const
const std::map< uint16_t, Mac48Address > & GetStaList(uint8_t linkId) const
Get a const reference to the map of associated stations on the given link.
void NotifyAckTimeoutStartNow(Time duration)
Notify that ack timer has started for the given duration.
void NotifyCtsTimeoutStartNow(Time duration)
Notify that CTS timer has started for the given duration.
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
bool IsRunning() const
This method is syntactic sugar for !IsExpired().
std::set< Mac48Address > m_sentRtsTo
the STA(s) which we sent an RTS to (waiting for CTS)
void DoCtsTimeout(Ptr< WifiPsdu > psdu)
Take required actions when the CTS timer fired after sending an RTS to protect the given PSDU expires...
uint8_t m_linkId
the ID of the link this object is associated with
Ptr< WifiMac > m_mac
the MAC layer on this station
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager() const
virtual void Reset()
Reset this frame exchange manager.
Mac48Address m_self
the MAC address of this device
virtual void StartProtection(const WifiTxParameters &txParams)
Start the protection mechanism indicated by the given TX parameters.
uint16_t m_allowedWidth
the allowed width in MHz for the current transmission
WifiTxTimer m_txTimer
the timer set upon frame transmission
std::set< Mac48Address > m_protectedStas
STAs that have replied to an RTS in this TXOP.
Ptr< WifiPhy > m_phy
the PHY layer on this station
Ptr< ChannelAccessManager > m_channelAccessManager
the channel access manager
virtual void RxStartIndication(WifiTxVector txVector, Time psduDuration)
virtual Time GetMuRtsDurationId(uint32_t muRtsSize, const WifiTxVector &muRtsTxVector, Time txDuration, Time response) const
Compute how to set the Duration/ID field of an MU-RTS Trigger Frame to send to protect a frame transm...
Ptr< ApWifiMac > m_apMac
MAC pointer (null if not an AP)
void DoDispose() override
Destructor implementation.
void Reset() override
Reset this frame exchange manager.
WifiMode GetCtsModeAfterMuRts() const
Ptr< WifiMpdu > PrepareMuBar(const WifiTxVector &responseTxVector, std::map< uint16_t, CtrlBAckRequestHeader > recipients) const
Build a MU-BAR Trigger Frame starting from the TXVECTOR used to respond to the MU-BAR (in case of mul...
virtual void SendMuRts(const WifiTxParameters &txParams)
Send an MU-RTS to begin an MU-RTS/CTS frame exchange protecting an MU PPDU.
WifiTxParameters m_txParams
the TX parameters for the current PPDU
void BlockAckTimeout(Ptr< WifiPsdu > psdu, const WifiTxVector &txVector) override
Called when the BlockAck timeout expires.
void RxStartIndication(WifiTxVector txVector, Time psduDuration) override
void CalculateAcknowledgmentTime(WifiAcknowledgment *acknowledgment) const override
Calculate the time required to acknowledge a frame according to the given acknowledgment method.
Ptr< WifiMpdu > m_triggerFrame
Trigger Frame being sent.
void SetMultiUserScheduler(const Ptr< MultiUserScheduler > muScheduler)
Set the Multi-user Scheduler associated with this Frame Exchange Manager.
WifiTxVector GetCtsTxVectorAfterMuRts(const CtrlTriggerHeader &trigger, uint16_t staId) const
Get the TXVECTOR that the station having the given station ID has to use to send a CTS frame after re...
void SetWifiMac(const Ptr< WifiMac > mac) override
Set the MAC layer to use.
Ptr< MultiUserScheduler > m_muScheduler
Multi-user Scheduler (HE APs only)
virtual void CtsAfterMuRtsTimeout(Ptr< WifiMpdu > muRts, const WifiTxVector &txVector)
Called when no CTS frame is received after an MU-RTS.
WifiTxVector m_trigVector
the TRIGVECTOR
void ProtectionCompleted() override
Transmit prepared frame upon successful protection mechanism.
static Ptr< WifiPsdu > GetPsduTo(Mac48Address to, const WifiPsduMap &psduMap)
Get the PSDU in the given PSDU map that is addressed to the given MAC address, if any,...
Ptr< StaWifiMac > m_staMac
MAC pointer (null if not a STA)
void CtsTimeout(Ptr< WifiMpdu > rts, const WifiTxVector &txVector) override
Called when the CTS timeout expires.
virtual void BlockAcksInTbPpduTimeout(WifiPsduMap *psduMap, std::size_t nSolicitedStations)
Take the necessary actions after that some BlockAck frames are missing in response to a DL MU PPDU.
EventId m_intraBssNavResetEvent
the event to reset the intra-BSS NAV after an RTS
bool StartFrameExchange(Ptr< QosTxop > edca, Time availableTime, bool initialFrame) override
Start a frame exchange (including protection frames and acknowledgment frames as needed) that fits wi...
void NormalAckTimeout(Ptr< WifiMpdu > mpdu, const WifiTxVector &txVector) override
Called when the Ack timeout expires.
virtual void BlockAckAfterTbPpduTimeout(Ptr< WifiPsdu > psdu, const WifiTxVector &txVector)
Take the necessary actions after that a Block Ack is missing after a TB PPDU solicited through a Trig...
virtual void TbPpduTimeout(WifiPsduMap *psduMap, std::size_t nSolicitedStations)
Take the necessary actions after that some TB PPDUs are missing in response to Trigger Frame.
void SendPsduMap()
Send the current PSDU map as a DL MU PPDU.
WifiPsduMap m_psduMap
the A-MPDU being transmitted
void RecordSentMuRtsTo(const WifiTxParameters &txParams)
Record the stations being solicited by an MU-RTS TF.
static TypeId GetTypeId()
Get the type ID.
Time m_intraBssNavEnd
intra-BSS NAV expiration time
EventId m_multiStaBaEvent
Sending a Multi-STA BlockAck event.
void SendPsduMapWithProtection(WifiPsduMap psduMap, WifiTxParameters &txParams)
Send a map of PSDUs as a DL MU PPDU.
void StartProtection(const WifiTxParameters &txParams) override
Start the protection mechanism indicated by the given TX parameters.
~HeFrameExchangeManager() override
void TransmissionSucceeded() override
Take necessary actions upon a transmission success.
static Time ConvertLSigLengthToHeTbPpduDuration(uint16_t length, const WifiTxVector &txVector, WifiPhyBand band)
void CtsTimeout(Ptr< WifiMpdu > rts, const WifiTxVector &txVector) override
Called when the CTS 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 TransmissionSucceeded() override
Take necessary actions upon a transmission success.
void SetWifiMac(const Ptr< WifiMac > mac) override
Set the MAC layer to use.
void ProtectionCompleted() override
Transmit prepared frame upon successful protection mechanism.
void ForwardMpduDown(Ptr< WifiMpdu > mpdu, WifiTxVector &txVector) override
Forward an MPDU down to the PHY layer.
void DoDispose() override
Destructor implementation.
bool StartFrameExchange(Ptr< QosTxop > edca, Time availableTime, bool initialFrame) override
Start a frame exchange (including protection frames and acknowledgment frames as needed) that fits wi...
void NotifyPacketDiscarded(Ptr< const WifiMpdu > mpdu) override
Pass the given MPDU, discarded because of the max retry limit was reached, to the MPDU dropped callba...
virtual void ForwardPsduDown(Ptr< const WifiPsdu > psdu, WifiTxVector &txVector)
Forward a PSDU down to the PHY layer.
void DequeuePsdu(Ptr< const WifiPsdu > psdu)
Dequeue the MPDUs of the given PSDU from the queue in which they are stored.
void ReleaseSequenceNumbers(Ptr< const WifiPsdu > psdu) const override
Make the sequence numbers of MPDUs included in the given PSDU available again if the MPDUs have never...
static Mac48Address GetBroadcast()
A tag to be attached to a response to a multi-user UL frame, that carries the SNR values with which t...
double Get(uint16_t staId) const
Return the SNR value for the given sender.
TxFormat
Enumeration of the possible transmission formats.
void AddHeader(const Header &header)
Add header to this packet.
void AddPacketTag(const Tag &tag) const
Add a packet tag.
uint32_t PeekHeader(Header &header) const
Deserialize but does not remove the header from the internal buffer.
void TransmissionFailed() override
Take necessary actions upon a transmission failure.
Ptr< QosTxop > m_edca
the EDCAF that gained channel access
Time GetRtsDurationId(const WifiTxVector &rtsTxVector, Time txDuration, Time response) const override
Compute how to set the Duration/ID field of an RTS frame to send to protect a frame transmitted with ...
Ptr< BlockAckManager > GetBaManager()
Get the Block Ack Manager associated with this QosTxop.
Ptr< WifiMpdu > PeekNextMpdu(uint8_t linkId, uint8_t tid=8, Mac48Address recipient=Mac48Address::GetBroadcast(), Ptr< const WifiMpdu > mpdu=nullptr)
Peek the next frame to transmit on the given link to the given receiver and of the given TID from the...
AcIndex GetAccessCategory() const
Get the access category of this object.
virtual Time GetRemainingTxop(uint8_t linkId) const
Return the remaining duration in the current TXOP on the given link.
Ptr< WifiMpdu > GetNextMpdu(uint8_t linkId, Ptr< WifiMpdu > peekedItem, WifiTxParameters &txParams, Time availableTime, bool initialFrame)
Prepare the frame to transmit on the given link starting from the MPDU that has been previously peeke...
std::pair< CtrlBAckRequestHeader, WifiMacHeader > PrepareBlockAckRequest(Mac48Address recipient, uint8_t tid) const
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
static Time Now()
Return the current simulation virtual time.
double Get() const
Return the SNR value.
Simulation virtual time values and global simulation resolution.
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
static Time Min()
Minimum representable Time Not to be confused with Min(Time,Time).
bool IsZero() const
Exactly equivalent to t == 0.
Time GetTxopLimit() const
Return the TXOP limit.
void UpdateFailedCw(uint8_t linkId)
Update the value of the CW variable for the given link to take into account a transmission failure.
void ResetCw(uint8_t linkId)
Update the value of the CW variable for the given link to take into account a transmission success or...
a unique identifier for an interface.
TypeId SetParent(TypeId tid)
Set the parent TypeId.
VhtFrameExchangeManager handles the frame exchange sequences for VHT stations.
Ptr< WifiPsdu > GetWifiPsdu(Ptr< WifiMpdu > mpdu, const WifiTxVector &txVector) const override
Get a PSDU containing the given MPDU.
static void SetQosAckPolicy(Ptr< WifiMpdu > item, const WifiAcknowledgment *acknowledgment)
Set the QoS Ack policy for the given MPDU, which must be a QoS data frame.
Ptr< HeConfiguration > GetHeConfiguration() const
OriginatorAgreementOptConstRef GetBaAgreementEstablishedAsOriginator(Mac48Address recipient, uint8_t tid) const
Ptr< QosTxop > GetQosTxop(AcIndex ac) const
Accessor for a specified EDCA object.
represent a single transmission mode
Time GetSlot() const
Return the slot duration for this PHY.
Time GetSifs() const
Return the Short Interframe Space (SIFS) for this PHY.
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
WifiPhyBand GetPhyBand() const
Get the configured Wi-Fi band.
Ptr< PhyEntity > GetPhyEntity(WifiModulationClass modulation) const
Get the supported PHY entity corresponding to the modulation class.
static Time CalculatePhyPreambleAndHeaderDuration(const WifiTxVector &txVector)
std::set< uint8_t > GetTids() const
Get the set of TIDs of the QoS Data frames included in the PSDU.
const WifiMacHeader & GetHeader(std::size_t i) const
Get the header of the i-th MPDU.
Time GetDuration() const
Get the duration from the Duration/ID field, which is common to all the MPDUs.
std::vector< Ptr< WifiMpdu > >::const_iterator end() const
Return a const iterator to past-the-last MPDU.
std::vector< Ptr< WifiMpdu > >::const_iterator begin() const
Return a const iterator to the first MPDU.
Mac48Address GetAddr2() const
Get the Transmitter Address (TA), which is common to all the MPDUs.
uint32_t GetSize() const
Return the size of the PSDU in bytes.
Ptr< const Packet > GetPayload(std::size_t i) const
Get the payload of the i-th MPDU.
Mac48Address GetAddr1() const
Get the Receiver Address (RA), which is common to all the MPDUs.
void SetDuration(Time duration)
Set the Duration/ID field on all the MPDUs.
std::size_t GetNMpdus() const
Return the number of MPDUs constituting the PSDU.
This class stores the TX parameters (TX vector, protection mechanism, acknowledgment mechanism,...
uint32_t GetSizeIfAddMpdu(Ptr< const WifiMpdu > mpdu) const
Get the size in bytes of the frame in case the given MPDU is added.
std::unique_ptr< WifiProtection > m_protection
protection method
std::unique_ptr< WifiAcknowledgment > m_acknowledgment
acknowledgment method
Time m_txDuration
TX duration of the frame.
WifiTxVector m_txVector
TXVECTOR of the frame being prepared.
void AddMpdu(Ptr< const WifiMpdu > mpdu)
Record that an MPDU is being added to the current frame.
void Clear()
Reset the TX parameters.
bool IsRunning() const
Return true if the timer is running.
Reason
The reason why the timer was started.
@ WAIT_BLOCK_ACK_AFTER_TB_PPDU
@ WAIT_NORMAL_ACK_AFTER_DL_MU_PPDU
@ WAIT_QOS_NULL_AFTER_BSRP_TF
@ WAIT_TB_PPDU_AFTER_BASIC_TF
@ WAIT_BLOCK_ACKS_IN_TB_PPDU
const std::set< Mac48Address > & GetStasExpectedToRespond() const
void Set(Reason reason, const Time &delay, const std::set< Mac48Address > &from, MEM mem_ptr, OBJ obj, Args... args)
This method is called when a frame soliciting a response is transmitted.
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
void SetTxPowerLevel(uint8_t powerlevel)
Sets the selected transmission power level.
void SetChannelWidth(uint16_t channelWidth)
Sets the selected channelWidth (in MHz)
uint8_t GetBssColor() const
Get the BSS color.
void SetGuardInterval(uint16_t guardInterval)
Sets the guard interval duration (in nanoseconds)
void SetTriggerResponding(bool triggerResponding)
Set the Trigger Responding parameter to the given value.
WifiMode GetMode(uint16_t staId=SU_STA_ID) const
If this TX vector is associated with an SU PPDU, return the selected payload transmission mode.
void SetHeMuUserInfo(uint16_t staId, HeMuUserInfo userInfo)
Set the HE MU user-specific transmission information for the given STA-ID.
WifiPreamble GetPreambleType() const
void SetAggregation(bool aggregation)
Sets if PSDU contains A-MPDU.
const HeMuUserInfoMap & GetHeMuUserInfoMap() const
Get a const reference to the map HE MU user-specific transmission information indexed by STA-ID.
WifiModulationClass GetModulationClass() const
Get the modulation class specified by this TXVECTOR.
void SetLength(uint16_t length)
Set the LENGTH field of the L-SIG.
void SetSigBMode(const WifiMode &mode)
Set the MCS used for SIG-B.
void SetBssColor(uint8_t color)
Set the BSS color.
uint16_t GetChannelWidth() const
void SetMode(WifiMode mode)
Sets the selected payload transmission mode.
void SetPreambleType(WifiPreamble preamble)
Sets the preamble type.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
#define NS_ABORT_IF(cond)
Abnormal program termination if a condition is true.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_WARN(msg)
Use NS_LOG to output a message of level LOG_WARN.
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Time Now()
create an ns3::Time instance which contains the current simulation time.
Time Seconds(double value)
Construct a Time in the indicated unit.
AcIndex
This enumeration defines the Access Categories as an enumeration with values corresponding to the AC ...
@ WIFI_PHY_BAND_2_4GHZ
The 2.4 GHz band.
@ WIFI_MOD_CLASS_VHT
VHT (Clause 22)
Declaration of ns3::HePhy class and ns3::HeSigAParameters struct.
void(* Time)(Time oldValue, Time newValue)
TracedValue callback signature for Time.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
static const uint16_t WIFI_MAC_FCS_LENGTH
The length in octets of the IEEE 802.11 MAC FCS field.
bool IsTrigger(const WifiPsduMap &psduMap)
uint32_t GetBlockAckRequestSize(BlockAckReqType type)
Return the total BlockAckRequest size (including FCS trailer).
uint32_t GetMuBarSize(std::list< BlockAckReqType > types)
Return the total MU-BAR size (including FCS trailer).
const std::map< AcIndex, WifiAc > wifiAcList
Map containing the four ACs in increasing order of priority (according to Table 10-1 "UP-to-AC Mappin...
uint32_t GetBlockAckSize(BlockAckType type)
Return the total BlockAck size (including FCS trailer).
bool IsDlMu(WifiPreamble preamble)
Return true if a preamble corresponds to a downlink multi-user transmission.
uint32_t GetAckSize()
Return the total Ack size (including FCS trailer).
bool IsTrigger(const WifiConstPsduMap &psduMap)
static constexpr uint16_t SU_STA_ID
STA_ID to identify a single user (SU)
uint32_t GetCtsSize()
Return the total CTS size (including FCS trailer).
std::unordered_map< uint16_t, Ptr< WifiPsdu > > WifiPsduMap
Map of PSDUs indexed by STA-ID.
U * PeekPointer(const Ptr< U > &p)
std::vector< uint8_t > m_bitmapLen
Length (bytes) of included bitmaps.
RxSignalInfo structure containing info on the received signal.
double snr
SNR in linear scale.
WifiAcknowledgment is an abstract base struct.
Time acknowledgmentTime
time required by the acknowledgment method
const Method method
acknowledgment method
WifiDlMuAggregateTf specifies that a DL MU PPDU made of PSDUs including each a MU-BAR Trigger Frame i...
std::map< Mac48Address, BlockAckInfo > stationsReplyingWithBlockAck
Set of stations replying with a BlockAck frame.
WifiDlMuBarBaSequence specifies that a DL MU PPDU is acknowledged through a sequence of BlockAckReq a...
WifiDlMuTfMuBar specifies that a DL MU PPDU is followed after a SIFS duration by a MU-BAR Trigger Fra...
WifiMuRtsCtsProtection specifies that MU-RTS/CTS protection method is used.
WifiNoAck specifies that no acknowledgment is required.
WifiNoProtection specifies that no protection method is used.
WifiProtection is an abstract base struct.
const Method method
protection method
WifiUlMuMultiStaBa specifies that a Basic Trigger Frame is being sent to solicit TB PPDUs that will b...
BlockAckType baType
BlockAck type.
std::map< std::pair< Mac48Address, uint8_t >, std::size_t > stationsReceivingMultiStaBa
Map (originator, tid) pairs to the their index in baType.