27#include "ns3/ap-wifi-mac.h"
29#include "ns3/recipient-block-ack-agreement.h"
30#include "ns3/snr-tag.h"
31#include "ns3/sta-wifi-mac.h"
36#undef NS_LOG_APPEND_CONTEXT
37#define NS_LOG_APPEND_CONTEXT std::clog << "[link=" << +m_linkId << "][mac=" << m_self << "] "
49 static TypeId tid =
TypeId(
"ns3::HeFrameExchangeManager")
51 .AddConstructor<HeFrameExchangeManager>()
52 .SetGroupName(
"Wifi");
57 : m_triggerFrameInAmpdu(false)
71 if (
m_mac->GetHeConfiguration()->GetMpduBufferSize() > 64)
105 "A Multi-User Scheduler can only be aggregated to an HE AP");
127 (mpdu->GetHeader().IsQosData() && !mpdu->GetHeader().GetAddr1().IsGroup() &&
129 mpdu->GetHeader().GetQosTid()))))
145 "The Multi-user Scheduler returned DL_MU_TX with empty psduMap, do not transmit");
156 auto packet = Create<Packet>();
158 auto trigger = Create<WifiMpdu>(packet,
m_muScheduler->GetUlMuInfo().macHdr);
181 NS_LOG_DEBUG(
"Block Ack Manager returned no frame to send");
185 if (peekedItem->GetHeader().IsBlockAckReq())
191 NS_ASSERT(peekedItem->GetHeader().IsTrigger());
206#ifdef NS3_BUILD_PROFILE_DEBUG
211 for (
const auto& psdu : psduMap)
215 NS_ASSERT(mpdu->GetHeader().IsCtl() || !mpdu->GetHeader().HasData() ||
255 auto it = std::find_if(
258 [&to](std::pair<uint16_t,
Ptr<WifiPsdu>> psdu) { return psdu.second->GetAddr1() == to; });
259 if (it != psduMap.end())
315 std::set<uint8_t> tids = psdu.second->
GetTids();
317 "Acknowledgment method incompatible with a Multi-TID A-MPDU");
318 uint8_t tid = *tids.begin();
322 m_mac->GetQosTxop(tid)->PrepareBlockAckRequest(psdu.second->
GetAddr1(), tid));
335 mpdu = *psdu->
begin();
361 std::map<uint16_t, CtrlBAckRequestHeader> recipients;
372 staIt->second.blockAckTxVector.GetHeMuUserInfo(staId));
373 recipients.emplace(staId, staIt->second.barHeader);
445 auto psduMapIt = std::find_if(
m_psduMap.begin(),
448 return psdu.second->GetAddr1() == station.first;
453 std::vector<Ptr<WifiMpdu>> mpduList(psduMapIt->second->begin(),
454 psduMapIt->second->end());
455 NS_ASSERT(mpduList.size() == psduMapIt->second->GetNMpdus());
458 station.second.blockAckTxVector.SetLength(acknowledgment->
ulLength);
459 mpduList.push_back(
PrepareMuBar(station.second.blockAckTxVector,
460 {{psduMapIt->first, station.second.barHeader}}));
461 psduMapIt->second = Create<WifiPsdu>(std::move(mpduList));
464 station.second.blockAckTxVector.GetHeMuUserInfo(psduMapIt->first));
469 &acknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
479 (mpdu = *m_psduMap.begin()->second->begin())->GetHeader().IsTrigger());
485 m_staExpectTbPpduFrom.clear();
489 m_staExpectTbPpduFrom.insert(station.first.first);
501 m_muScheduler->GetUlMuInfo().trigger.GetUlLength(),
503 m_phy->GetPhyBand());
504 acknowledgment->
acknowledgmentTime += m_mac->GetWifiPhy()->GetSifs() + tbPpduDuration;
508 m_trigVector = GetTrigVector(m_muScheduler->GetUlMuInfo().trigger);
514 !m_txParams.m_txVector.IsUlMu() && m_psduMap.size() == 1 &&
516 (*m_psduMap.begin()->second->begin())->GetHeader().IsTrigger())
518 CtrlTriggerHeader& trigger = m_muScheduler->GetUlMuInfo().trigger;
523 m_staExpectTbPpduFrom.clear();
525 for (
const auto& userInfo : trigger)
527 auto staIt = m_apMac->GetStaList().find(userInfo.GetAid12());
528 NS_ASSERT(staIt != m_apMac->GetStaList().end());
529 m_staExpectTbPpduFrom.insert(staIt->second);
534 WifiNoAck* acknowledgment =
static_cast<WifiNoAck*
>(m_txParams.m_acknowledgment.get());
535 txVector = trigger.GetHeTbTxVector(trigger.begin()->GetAid12());
537 m_mac->GetWifiPhy()->GetSifs() +
540 m_phy->GetPhyBand());
543 responseTxVector = &txVector;
544 m_trigVector = GetTrigVector(m_muScheduler->GetUlMuInfo().trigger);
549 else if (m_txParams.m_txVector.IsUlMu() &&
554 NS_ASSERT(m_staMac && m_staMac->IsAssociated());
555 txVector = GetWifiRemoteStationManager()->GetBlockAckTxVector(
556 m_psduMap.begin()->second->GetAddr1(),
557 m_txParams.m_txVector);
558 responseTxVector = &txVector;
563 else if (m_txParams.m_txVector.IsUlMu() &&
570 NS_ABORT_MSG(
"Unable to handle the selected acknowledgment method ("
571 << m_txParams.m_acknowledgment.get() <<
")");
576 for (
const auto& psdu : m_psduMap)
578 psduMap.emplace(psdu.first, psdu.second);
582 if (m_txParams.m_txVector.IsUlMu())
585 m_txParams.m_txVector,
586 m_phy->GetPhyBand());
591 m_phy->CalculateTxDuration(psduMap, m_txParams.m_txVector, m_phy->GetPhyBand());
594 Time durationId = GetPsduDurationId(txDuration, m_txParams);
595 for (
auto& psdu : m_psduMap)
597 psdu.second->SetDuration(durationId);
603 if (!m_txParams.m_txVector.IsUlMu())
610 Time timeout = txDuration + m_phy->GetSifs() + m_phy->GetSlot() +
611 m_phy->CalculatePhyPreambleAndHeaderDuration(*responseTxVector);
612 m_channelAccessManager->NotifyAckTimeoutStartNow(
timeout);
619 m_txTimer.Set(timerType,
624 m_txParams.m_txVector);
628 m_txTimer.Set(timerType,
633 m_txParams.m_txVector);
636 m_txTimer.Set(timerType,
641 &m_staExpectTbPpduFrom,
642 m_staExpectTbPpduFrom.size());
646 m_txTimer.Set(timerType,
651 &m_staExpectTbPpduFrom,
652 m_staExpectTbPpduFrom.size());
655 m_txTimer.Set(timerType,
659 m_psduMap.begin()->second,
660 m_txParams.m_txVector);
669 ForwardPsduMapDown(psduMap, m_txParams.m_txVector);
677 hePhy->SetTrigVector(m_trigVector, m_txTimer.GetDelayLeft());
694 auto sigBMode = hePhy->GetSigBMode(txVector);
698 for (
const auto& psdu : psduMap)
700 NS_LOG_DEBUG(
"Transmitting: [STAID=" << psdu.first <<
", " << *psdu.second <<
"]");
703 for (
const auto& psdu : psduMap)
705 NotifyTxToEdca(psdu.second);
707 if (psduMap.size() > 1 || psduMap.begin()->second->IsAggregate() ||
708 psduMap.begin()->second->IsSingle())
713 m_phy->Send(psduMap, txVector);
717HeFrameExchangeManager::PrepareMuBar(
const WifiTxVector& responseTxVector,
718 std::map<uint16_t, CtrlBAckRequestHeader> recipients)
const
725 SetTargetRssi(muBar);
731 for (
auto& userInfo : muBar)
733 auto recipientIt = recipients.find(userInfo.GetAid12());
734 NS_ASSERT(recipientIt != recipients.end());
737 userInfo.SetMuBarTriggerDepUserInfo(recipientIt->second);
749 rxAddress = Mac48Address::GetBroadcast();
754 rxAddress = m_apMac->GetStaList().at(recipients.begin()->first);
766 return Create<WifiMpdu>(bar, hdr);
778 if (acknowledgment->
method == WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE)
796 m_phy->CalculateTxDuration(
GetAckSize(), info.ackTxVector, m_phy->GetPhyBand());
803 duration += m_phy->GetSifs() + m_phy->CalculateTxDuration(
GetBlockAckSize(info.baType),
804 info.blockAckTxVector,
805 m_phy->GetPhyBand());
810 const auto& info = stations.second;
811 duration += m_phy->GetSifs() +
813 info.blockAckReqTxVector,
814 m_phy->GetPhyBand()) +
817 info.blockAckTxVector,
818 m_phy->GetPhyBand());
826 else if (acknowledgment->
method == WifiAcknowledgment::DL_MU_TF_MU_BAR)
835 const auto& info = stations.second;
836 NS_ASSERT(info.blockAckTxVector.GetHeMuUserInfoMap().size() == 1);
837 uint16_t staId = info.blockAckTxVector.GetHeMuUserInfoMap().begin()->first;
839 info.blockAckTxVector,
843 if (currBlockAckDuration > duration)
845 duration = currBlockAckDuration;
852 ->second.blockAckTxVector;
853 std::tie(dlMuTfMuBarAcknowledgment->
ulLength, duration) =
854 HePhy::ConvertHeTbPpduDurationToLSigLength(duration, txVector, m_phy->GetPhyBand());
860 muBarSize = MpduAggregator::GetSizeIfAggregated(muBarSize, 0);
864 m_phy->CalculateTxDuration(muBarSize,
866 m_phy->GetPhyBand()) +
867 m_phy->GetSifs() + duration;
872 else if (acknowledgment->
method == WifiAcknowledgment::DL_MU_AGGREGATE_TF)
882 const auto& info = stations.second;
883 NS_ASSERT(info.blockAckTxVector.GetHeMuUserInfoMap().size() == 1);
884 uint16_t staId = info.blockAckTxVector.GetHeMuUserInfoMap().begin()->first;
886 info.blockAckTxVector,
890 if (currBlockAckDuration > duration)
892 duration = currBlockAckDuration;
900 std::tie(dlMuAggrTfAcknowledgment->
ulLength, duration) =
901 HePhy::ConvertHeTbPpduDurationToLSigLength(duration, txVector, m_phy->GetPhyBand());
907 else if (acknowledgment->
method == WifiAcknowledgment::UL_MU_MULTI_STA_BA)
913 m_phy->GetPhyBand());
919 else if (acknowledgment->
method == WifiAcknowledgment::ACK_AFTER_TB_PPDU)
928 VhtFrameExchangeManager::CalculateAcknowledgmentTime(acknowledgment);
933HeFrameExchangeManager::GetTxDuration(
uint32_t ppduPayloadSize,
939 return VhtFrameExchangeManager::GetTxDuration(ppduPayloadSize, receiver, txParams);
946 txParams.
m_acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF)
956 MpduAggregator::GetSizeIfAggregated(info->second.muBarSize, ppduPayloadSize);
959 uint16_t staId = (txParams.
m_txVector.
IsDlMu() ? m_apMac->GetAssociationId(receiver, m_linkId)
960 : m_staMac->GetAssociationId());
961 Time psduDuration = m_phy->CalculateTxDuration(ppduPayloadSize,
971 const std::set<Mac48Address>* staMissedTbPpduFrom,
972 std::size_t nSolicitedStations)
974 NS_LOG_FUNCTION(
this << psduMap << staMissedTbPpduFrom->size() << nSolicitedStations);
978 psduMap->begin()->second->GetHeader(0).IsTrigger());
981 NS_ASSERT(!staMissedTbPpduFrom->empty());
984 if (staMissedTbPpduFrom->size() == nSolicitedStations)
987 m_edca->UpdateFailedCw(m_linkId);
989 TransmissionFailed();
991 else if (!m_multiStaBaEvent.IsRunning())
993 m_edca->ResetCw(m_linkId);
994 TransmissionSucceeded();
1001HeFrameExchangeManager::BlockAcksInTbPpduTimeout(
1003 const std::set<Mac48Address>* staMissedBlockAckFrom,
1004 std::size_t nSolicitedStations)
1009 NS_ASSERT(m_txParams.m_acknowledgment &&
1010 (m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF ||
1011 m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_TF_MU_BAR));
1014 NS_ASSERT(!staMissedBlockAckFrom->empty());
1018 if (staMissedBlockAckFrom->size() == nSolicitedStations)
1022 GetWifiRemoteStationManager()->ReportDataFailed(*psduMap->begin()->second->begin());
1031 m_triggerFrame =
nullptr;
1033 for (
const auto& sta : *staMissedBlockAckFrom)
1042 MissedBlockAck(psdu, m_txParams.m_txVector, psduResetCw);
1043 resetCw = resetCw || psduResetCw;
1050 m_edca->ResetCw(m_linkId);
1054 m_edca->UpdateFailedCw(m_linkId);
1057 if (staMissedBlockAckFrom->size() == nSolicitedStations)
1060 TransmissionFailed();
1064 TransmissionSucceeded();
1077 GetWifiRemoteStationManager()->ReportDataFailed(*psdu->
begin());
1079 MissedBlockAck(psdu, m_txParams.m_txVector, resetCw);
1094 VhtFrameExchangeManager::NormalAckTimeout(mpdu, txVector);
1099 for (
auto& psdu : m_psduMap)
1103 if (mpdu->IsQueued())
1105 mpdu->GetHeader().SetRetry();
1117 VhtFrameExchangeManager::BlockAckTimeout(psdu, txVector);
1122 for (
auto& psdu : m_psduMap)
1126 if (mpdu->IsQueued())
1128 mpdu->GetHeader().SetRetry();
1143 for (
const auto& userInfoField : trigger)
1146 {userInfoField.GetRuAllocation(),
1147 HePhy::GetHeMcs(userInfoField.GetUlMcs()),
1148 userInfoField.GetNss()});
1160 uint16_t staId = m_staMac->GetAssociationId();
1167 NS_ASSERT_MSG(heConfiguration,
"This STA has to be an HE station to send an HE TB PPDU");
1170 if (userInfoIt->IsUlTargetRssiMaxTxPower())
1172 NS_LOG_LOGIC(
"AP requested using the max transmit power (" << m_phy->GetTxPowerEnd()
1178 uint8_t powerLevel = GetWifiRemoteStationManager()->GetDefaultTxPowerLevel();
1198 static_cast<int8_t>(GetWifiRemoteStationManager()->GetMostRecentRssi(
1200 double reqTxPowerDbm =
static_cast<double>(userInfoIt->GetUlTargetRssi() + pathLossDb);
1203 uint8_t numPowerLevels = m_phy->GetNTxPower();
1204 if (numPowerLevels > 1)
1206 double stepDbm = (m_phy->GetTxPowerEnd() - m_phy->GetTxPowerStart()) / (numPowerLevels - 1);
1207 powerLevel =
static_cast<uint8_t
>(
1208 ceil((reqTxPowerDbm - m_phy->GetTxPowerStart()) /
1210 if (powerLevel > numPowerLevels)
1212 powerLevel = numPowerLevels;
1215 if (reqTxPowerDbm > m_phy->GetPowerDbm(powerLevel))
1218 << reqTxPowerDbm <<
"dBm) cannot be satisfied (max: " << m_phy->GetTxPowerEnd()
1223 <<
"input {pathLoss=" << pathLossDb <<
"dB, reqTxPower=" << reqTxPowerDbm <<
"dBm}"
1224 <<
" output {powerLevel=" << +powerLevel <<
" -> "
1225 << m_phy->GetPowerDbm(powerLevel) <<
"dBm}"
1226 <<
" PHY power capa {min=" << m_phy->GetTxPowerStart() <<
"dBm, max="
1227 << m_phy->GetTxPowerEnd() <<
"dBm, levels:" << +numPowerLevels <<
"}");
1239 m_phy->GetPowerDbm(GetWifiRemoteStationManager()->GetDefaultTxPowerLevel())));
1240 for (
auto& userInfo : trigger)
1242 const auto staList = m_apMac->GetStaList();
1243 auto itAidAddr = staList.find(userInfo.GetAid12());
1246 GetWifiRemoteStationManager()->GetMostRecentRssi(itAidAddr->second));
1247 rssi = (rssi >= -20)
1249 : ((rssi <= -110) ? -110 : rssi);
1250 userInfo.SetUlTargetRssi(rssi);
1261 txParams.
m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
1274 receiver = staInfo.first.first;
1275 uint8_t tid = staInfo.first.second;
1276 std::size_t index = staInfo.second;
1278 blockAck.
SetAid11(m_apMac->GetAssociationId(receiver, m_linkId), index);
1284 NS_LOG_DEBUG(
"Multi-STA Block Ack: Sending All-ack to=" << receiver);
1292 NS_LOG_DEBUG(
"Multi-STA Block Ack: Sending Ack to=" << receiver);
1300 auto addressTidPair = staInfo.first;
1301 auto agreementIt = m_agreements.find(addressTidPair);
1302 NS_ASSERT(agreementIt != m_agreements.end());
1303 agreementIt->second.FillBlockAckBitmap(&blockAck, index);
1304 NS_LOG_DEBUG(
"Multi-STA Block Ack: Sending Block Ack with seq="
1306 <<
" tid=" << +tid);
1314 : Mac48Address::GetBroadcast());
1329 m_phy->GetPhyBand());
1334 psdu->
SetDuration(GetPsduDurationId(txDuration, params));
1342 m_edca->ResetCw(m_linkId);
1344 Simulator::Schedule(txDuration, &HeFrameExchangeManager::TransmissionSucceeded,
this);
1353 NS_ASSERT(m_staMac && m_staMac->IsAssociated());
1355 NS_LOG_DEBUG(
"Received a Trigger Frame (basic variant) soliciting a transmission");
1359 NS_LOG_DEBUG(
"Carrier Sensing required and channel busy, do nothing");
1369 std::vector<uint8_t> tids;
1370 uint16_t staId = m_staMac->GetAssociationId();
1373 for (uint8_t i = 0; i < 4; i++)
1376 tids.push_back(acIt->second.GetHighTid());
1377 tids.push_back(acIt->second.GetLowTid());
1389 Time ppduDuration = HePhy::ConvertLSigLengthToHeTbPpduDuration(trigger.
GetUlLength(),
1391 m_phy->GetPhyBand());
1393 for (
const auto& tid : tids)
1409 TryAddMpdu(mpdu, txParams, ppduDuration))
1424 std::vector<Ptr<WifiMpdu>> mpduList =
1425 m_mpduAggregator->GetNextAmpdu(item, txParams, ppduDuration);
1426 psdu = (mpduList.size() > 1 ? Create<WifiPsdu>(std::move(mpduList))
1427 : Create<WifiPsdu>(item,
true));
1436 SendPsduMapWithProtection(
WifiPsduMap{{staId, psdu}}, txParams);
1441 SendQosNullFramesInTbPpdu(trigger, hdr);
1451 NS_ASSERT(m_staMac && m_staMac->IsAssociated());
1457 NS_LOG_DEBUG(
"Carrier Sensing required and channel busy (TA="
1458 << hdr.
GetAddr2() <<
", TxopHolder=" << m_txopHolder
1459 <<
", NAV end=" << m_navEnd.As(Time::S) <<
"), do nothing");
1481 Time ppduDuration = HePhy::ConvertLSigLengthToHeTbPpduDuration(trigger.
GetUlLength(),
1483 m_phy->GetPhyBand());
1487 std::vector<Ptr<WifiMpdu>> mpduList;
1492 IsWithinSizeAndTimeLimits(
1493 txParams.
GetSizeIfAddMpdu(mpdu = Create<WifiMpdu>(Create<Packet>(), header)),
1498 if (!m_mac->GetQosTxop(tid)->GetBaAgreementEstablished(hdr.
GetAddr2(), tid))
1500 NS_LOG_DEBUG(
"Skipping tid=" << +tid <<
" because no agreement established");
1505 NS_LOG_DEBUG(
"Aggregating a QoS Null frame with tid=" << +tid);
1513 UpdateTxDuration(mpdu->GetHeader().GetAddr1(), txParams);
1514 mpduList.push_back(mpdu);
1518 if (mpduList.empty())
1520 NS_LOG_DEBUG(
"Not enough time to send a QoS Null frame");
1524 Ptr<WifiPsdu> psdu = (mpduList.size() > 1 ? Create<WifiPsdu>(std::move(mpduList))
1525 : Create<WifiPsdu>(mpduList.front(),
true));
1526 uint16_t staId = m_staMac->GetAssociationId();
1527 SendPsduMapWithProtection(
WifiPsduMap{{staId, psdu}}, txParams);
1539 else if (!txVector.
IsUlMu())
1541 VhtFrameExchangeManager::SetTxopHolder(psdu, txVector);
1552 NS_ASSERT(mpdu->GetHeader().GetAddr1().IsGroup() || mpdu->GetHeader().GetAddr1() == m_self);
1556 if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
1557 m_txTimer.GetReason() == WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF)
1560 NS_ASSERT(m_txParams.m_acknowledgment &&
1561 m_txParams.m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
1566 if (m_staExpectTbPpduFrom.find(sender) == m_staExpectTbPpduFrom.end())
1568 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
1574 NS_LOG_DEBUG(
"Received a BlockAckReq in a TB PPDU from " << sender);
1577 mpdu->GetPacket()->PeekHeader(blockAckReq);
1580 auto agreementIt = m_agreements.find({sender, tid});
1581 NS_ASSERT(agreementIt != m_agreements.end());
1587 GetBlockAckType(sender, tid).m_bitmapLen.at(0));
1589 m_muSnrTag.Set(staId, rxSignalInfo.
snr);
1593 NS_LOG_DEBUG(
"Received an S-MPDU in a TB PPDU from " << sender <<
" (" << *mpdu <<
")");
1596 auto agreementIt = m_agreements.find({sender, tid});
1597 NS_ASSERT(agreementIt != m_agreements.end());
1598 agreementIt->second.NotifyReceivedMpdu(mpdu);
1604 m_muSnrTag.Set(staId, rxSignalInfo.
snr);
1613 VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
1620 m_multiStaBaEvent = Simulator::Schedule(m_phy->GetSifs(),
1621 &HeFrameExchangeManager::SendMultiStaBlockAck,
1623 std::cref(m_txParams));
1627 m_staExpectTbPpduFrom.erase(sender);
1629 if (m_staExpectTbPpduFrom.empty())
1633 m_channelAccessManager->NotifyAckTimeoutResetNow();
1635 if (!m_multiStaBaEvent.IsRunning())
1640 m_edca->ResetCw(m_linkId);
1641 TransmissionSucceeded();
1649 if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
1650 m_txTimer.GetReason() == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF &&
1655 if (m_staExpectTbPpduFrom.find(sender) == m_staExpectTbPpduFrom.end())
1657 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
1662 NS_LOG_WARN(
"No QoS Null frame in the received MPDU");
1666 NS_LOG_DEBUG(
"Received a QoS Null frame in a TB PPDU from " << sender);
1669 m_staExpectTbPpduFrom.erase(sender);
1671 if (m_staExpectTbPpduFrom.empty())
1675 m_channelAccessManager->NotifyAckTimeoutResetNow();
1679 m_edca->ResetCw(m_linkId);
1680 TransmissionSucceeded();
1689 if (hdr.
IsCts() && m_txTimer.IsRunning() &&
1690 m_txTimer.GetReason() == WifiTxTimer::WAIT_CTS && m_psduMap.size() == 1)
1695 Mac48Address sender = m_psduMap.begin()->second->GetAddr1();
1699 mpdu->GetPacket()->PeekPacketTag(tag);
1700 GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
1701 GetWifiRemoteStationManager()->ReportRtsOk(m_psduMap.begin()->second->GetHeader(0),
1707 m_channelAccessManager->NotifyCtsTimeoutResetNow();
1708 Simulator::Schedule(m_phy->GetSifs(), &HeFrameExchangeManager::SendPsduMap,
this);
1710 else if (hdr.
IsAck() && m_txTimer.IsRunning() &&
1711 m_txTimer.GetReason() == WifiTxTimer::WAIT_NORMAL_ACK_AFTER_DL_MU_PPDU)
1715 NS_ASSERT(m_txParams.m_acknowledgment->method ==
1716 WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE);
1722 uint16_t staId = m_apMac->GetAssociationId(
1725 auto it = m_psduMap.find(staId);
1730 mpdu->GetPacket()->PeekPacketTag(tag);
1731 ReceivedNormalAck(*it->second->begin(),
1732 m_txParams.m_txVector,
1745 m_txTimer.GetReason() == WifiTxTimer::WAIT_BLOCK_ACKS_IN_TB_PPDU)
1748 NS_LOG_DEBUG(
"Received BlockAck in TB PPDU from=" << sender);
1751 mpdu->GetPacket()->PeekPacketTag(tag);
1755 mpdu->GetPacket()->PeekHeader(blockAck);
1757 std::pair<uint16_t, uint16_t> ret =
1758 GetBaManager(tid)->NotifyGotBlockAck(blockAck, hdr.
GetAddr2(), {tid});
1759 GetWifiRemoteStationManager()->ReportAmpduTxStatus(hdr.
GetAddr2(),
1764 m_txParams.m_txVector);
1767 if (m_staExpectTbPpduFrom.erase(sender) == 0)
1769 NS_LOG_WARN(
"Received a BlockAck from an unexpected stations: " << sender);
1773 if (m_staExpectTbPpduFrom.empty())
1777 m_channelAccessManager->NotifyAckTimeoutResetNow();
1778 m_triggerFrame =
nullptr;
1780 m_edca->ResetCw(m_linkId);
1782 TransmissionSucceeded();
1785 else if (hdr.
IsBlockAck() && m_txTimer.IsRunning() &&
1786 m_txTimer.GetReason() == WifiTxTimer::WAIT_BLOCK_ACK_AFTER_TB_PPDU)
1789 mpdu->GetPacket()->PeekHeader(blockAck);
1792 "A Multi-STA BlockAck is expected after a TB PPDU");
1795 NS_ASSERT(m_staMac && m_staMac->IsAssociated());
1798 NS_LOG_DEBUG(
"The sender is not the AP we are associated with");
1802 uint16_t staId = m_staMac->GetAssociationId();
1805 if (indices.empty())
1807 NS_LOG_DEBUG(
"No Per AID TID Info subfield intended for me");
1812 mpdu->GetPacket()->PeekPacketTag(tag);
1815 for (
const auto& index : indices)
1822 NS_ABORT_IF(m_psduMap.empty() || m_psduMap.begin()->first != staId);
1823 GetBaManager(tid)->NotifyGotAck(*m_psduMap.at(staId)->begin());
1832 NS_ABORT_IF(m_psduMap.empty() || m_psduMap.begin()->first != staId);
1833 std::set<uint8_t> tids = m_psduMap.at(staId)->GetTids();
1834 NS_ABORT_MSG_IF(tids.size() > 1,
"Multi-TID A-MPDUs not supported yet");
1835 tid = *tids.begin();
1838 std::pair<uint16_t, uint16_t> ret =
1839 GetBaManager(tid)->NotifyGotBlockAck(blockAck,
1843 GetWifiRemoteStationManager()->ReportAmpduTxStatus(hdr.
GetAddr2(),
1848 m_txParams.m_txVector);
1851 if (m_psduMap.at(staId)->GetHeader(0).IsQosData() &&
1853 || std::any_of(blockAck.
GetBitmap(index).begin(),
1855 [](uint8_t b) { return b != 0; })))
1857 NS_ASSERT(m_psduMap.at(staId)->GetHeader(0).HasData());
1858 NS_ASSERT(m_psduMap.at(staId)->GetHeader(0).GetQosTid() == tid);
1863 m_mac->GetQosTxop(tid)->StartMuEdcaTimerNow(m_linkId);
1869 m_channelAccessManager->NotifyAckTimeoutResetNow();
1872 else if (hdr.
IsBlockAck() && m_txTimer.IsRunning() &&
1873 m_txTimer.GetReason() == WifiTxTimer::WAIT_BLOCK_ACK)
1879 VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
1892 m_triggerFrameInAmpdu =
true;
1897 mpdu->GetPacket()->PeekHeader(trigger);
1908 uint16_t staId = m_staMac->GetAssociationId();
1913 NS_LOG_DEBUG(
"Received MU-BAR Trigger Frame from=" << sender);
1914 GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
1922 auto agreementIt = m_agreements.find({sender, tid});
1924 if (agreementIt == m_agreements.end())
1926 NS_LOG_DEBUG(
"There's not a valid agreement for this BlockAckReq");
1933 Simulator::Schedule(m_phy->GetSifs(),
1934 &HeFrameExchangeManager::SendBlockAck,
1936 agreementIt->second,
1938 GetHeTbTxVector(trigger, hdr.
GetAddr2()),
1943 Simulator::Schedule(m_phy->GetSifs(),
1944 &HeFrameExchangeManager::ReceiveBasicTrigger,
1949 else if (trigger.
IsBsrp())
1951 Simulator::Schedule(m_phy->GetSifs(),
1952 &HeFrameExchangeManager::SendQosNullFramesInTbPpdu,
1961 VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
1969 VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
1977 const std::vector<bool>& perMpduStatus)
1979 std::set<uint8_t> tids = psdu->
GetTids();
1981 if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
1982 m_txTimer.GetReason() == WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF)
1985 NS_ASSERT(m_txParams.m_acknowledgment &&
1986 m_txParams.m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
1991 if (m_staExpectTbPpduFrom.find(sender) == m_staExpectTbPpduFrom.end())
1993 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
1997 NS_LOG_DEBUG(
"Received an A-MPDU in a TB PPDU from " << sender <<
" (" << *psdu <<
")");
1999 if (std::any_of(tids.begin(), tids.end(), [&psdu](uint8_t tid) {
2000 return psdu->GetAckPolicyForTid(tid) == WifiMacHeader::NORMAL_ACK;
2003 if (std::all_of(perMpduStatus.cbegin(), perMpduStatus.cend(), [](
bool v) { return v; }))
2014 for (
const auto& tid : tids)
2019 GetBlockAckType(sender, tid).m_bitmapLen.at(0));
2023 m_muSnrTag.Set(staId, rxSignalInfo.
snr);
2029 m_multiStaBaEvent = Simulator::Schedule(m_phy->GetSifs(),
2030 &HeFrameExchangeManager::SendMultiStaBlockAck,
2032 std::cref(m_txParams));
2036 m_staExpectTbPpduFrom.erase(sender);
2038 if (m_staExpectTbPpduFrom.empty())
2042 m_channelAccessManager->NotifyAckTimeoutResetNow();
2044 if (!m_multiStaBaEvent.IsRunning())
2049 m_edca->ResetCw(m_linkId);
2050 TransmissionSucceeded();
2058 if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
2059 m_txTimer.GetReason() == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF)
2063 if (m_staExpectTbPpduFrom.find(sender) == m_staExpectTbPpduFrom.end())
2065 NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
2069 return mpdu->GetHeader().IsQosData() && !mpdu->GetHeader().HasData();
2072 NS_LOG_WARN(
"No QoS Null frame in the received PSDU");
2076 NS_LOG_DEBUG(
"Received QoS Null frames in a TB PPDU from " << sender);
2079 m_staExpectTbPpduFrom.erase(sender);
2081 if (m_staExpectTbPpduFrom.empty())
2085 m_channelAccessManager->NotifyAckTimeoutResetNow();
2089 m_edca->ResetCw(m_linkId);
2090 TransmissionSucceeded();
2097 if (m_triggerFrameInAmpdu)
2100 auto psduIt = psdu->
begin();
2101 while (psduIt != psdu->
end())
2103 if ((*psduIt)->GetHeader().IsTrigger())
2105 ReceiveMpdu(*psduIt, rxSignalInfo, txVector,
false);
2110 m_triggerFrameInAmpdu =
false;
2115 VhtFrameExchangeManager::EndReceiveAmpdu(psdu, rxSignalInfo, txVector, perMpduStatus);
uint16_t GetAssociationId(Mac48Address addr, uint8_t linkId) const
void NotifyAckTimeoutStartNow(Time duration)
Notify that ack timer has started for the given duration.
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
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
uint16_t m_allowedWidth
the allowed width in MHz for the current transmission
WifiTxTimer m_txTimer
the timer set upon frame transmission
void SendRts(const WifiTxParameters &txParams)
Send RTS to begin RTS-CTS-Data-Ack transaction.
Ptr< WifiPhy > m_phy
the PHY layer on this station
Ptr< ChannelAccessManager > m_channelAccessManager
the channel access manager
Ptr< ApWifiMac > m_apMac
MAC pointer (null if not an AP)
bool SendMpduFromBaManager(Ptr< QosTxop > edca, Time availableTime, bool initialFrame) override
If the Block Ack Manager associated with the given EDCA has a BlockAckReq frame to transmit (the dura...
void DoDispose() override
Destructor implementation.
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...
WifiTxParameters m_txParams
the TX parameters for the current PPDU
void BlockAckTimeout(Ptr< WifiPsdu > psdu, const WifiTxVector &txVector) override
Called when the BlockAck timeout expires.
uint16_t GetSupportedBaBufferSize() const override
Get the maximum supported buffer size for a Block Ack agreement.
void CalculateAcknowledgmentTime(WifiAcknowledgment *acknowledgment) const override
Calculate the time required to acknowledge a frame according to the given acknowledgment method.
Ptr< WifiMpdu > m_triggerFrame
Trigger Frame being sent.
void SetMultiUserScheduler(const Ptr< MultiUserScheduler > muScheduler)
Set the Multi-user Scheduler associated with this Frame Exchange Manager.
virtual void TbPpduTimeout(WifiPsduMap *psduMap, const std::set< Mac48Address > *staMissedTbPpduFrom, std::size_t nSolicitedStations)
Take the necessary actions after that some TB PPDUs are missing in response to Trigger Frame.
void SetWifiMac(const Ptr< WifiMac > mac) override
Set the MAC layer to use.
Ptr< MultiUserScheduler > m_muScheduler
Multi-user Scheduler (HE APs only)
WifiTxVector m_trigVector
the TRIGVECTOR
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.
bool StartFrameExchange(Ptr< QosTxop > edca, Time availableTime, bool initialFrame) override
Start a frame exchange (including protection frames and acknowledgment frames as needed) that fits wi...
std::set< Mac48Address > m_staExpectTbPpduFrom
set of stations expected to send a TB PPDU
void NormalAckTimeout(Ptr< WifiMpdu > mpdu, const WifiTxVector &txVector) override
Called when the Ack timeout expires.
virtual void BlockAckAfterTbPpduTimeout(Ptr< WifiPsdu > psdu, const WifiTxVector &txVector)
Take the necessary actions after that a Block Ack is missing after a TB PPDU solicited through a Trig...
void SendPsduMap()
Send the current PSDU map as a DL MU PPDU.
WifiPsduMap m_psduMap
the A-MPDU being transmitted
static TypeId GetTypeId()
Get the type ID.
virtual void BlockAcksInTbPpduTimeout(WifiPsduMap *psduMap, const std::set< Mac48Address > *staMissedBlockAckFrom, std::size_t nSolicitedStations)
Take the necessary actions after that some BlockAck frames are missing in response to a DL MU PPDU.
EventId m_multiStaBaEvent
Sending a Multi-STA BlockAck event.
void SendPsduMapWithProtection(WifiPsduMap psduMap, WifiTxParameters &txParams)
Send a map of PSDUs as a DL MU PPDU.
~HeFrameExchangeManager() override
static Time ConvertLSigLengthToHeTbPpduDuration(uint16_t length, const WifiTxVector &txVector, WifiPhyBand band)
virtual bool SendMpduFromBaManager(Ptr< QosTxop > edca, Time availableTime, bool initialFrame)
If the Block Ack Manager associated with the given EDCA has a BlockAckReq frame to transmit (the dura...
void CtsTimeout(Ptr< WifiMpdu > rts, const WifiTxVector &txVector) override
Called when the CTS timeout expires.
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 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...
virtual void ForwardPsduDown(Ptr< const WifiPsdu > psdu, WifiTxVector &txVector)
Forward a PSDU down to the PHY layer.
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.
Smart pointer class similar to boost::intrusive_ptr.
Ptr< QosTxop > m_edca
the EDCAF that gained channel access
Ptr< BlockAckManager > GetBaManager()
Get the Block Ack Manager associated with this QosTxop.
void ScheduleBar(Ptr< const WifiMpdu > bar, bool skipIfNoDataQueued=false)
bool GetBaAgreementEstablished(Mac48Address address, uint8_t tid) const
Ptr< WifiMpdu > PeekNextMpdu(uint8_t linkId, uint8_t tid=8, Mac48Address recipient=Mac48Address::GetBroadcast(), Ptr< WifiMpdu > item=nullptr)
Peek the next frame to transmit on the given link to the given receiver and of the given TID from the...
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...
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Introspection did not find any typical Config paths.
double Get() const
Return the SNR value.
Simulation virtual time values and global simulation resolution.
static Time Min()
Minimum representable Time Not to be confused with Min(Time,Time).
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
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.
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.
void Set(Reason reason, const Time &delay, MEM mem_ptr, OBJ obj, Args... args)
This method is called when a frame soliciting a response is transmitted.
Reason
The reason why the timer was started.
@ WAIT_BLOCK_ACK_AFTER_TB_PPDU
@ WAIT_NORMAL_ACK_AFTER_DL_MU_PPDU
@ WAIT_QOS_NULL_AFTER_BSRP_TF
@ WAIT_TB_PPDU_AFTER_BASIC_TF
@ WAIT_BLOCK_ACKS_IN_TB_PPDU
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
void SetTxPowerLevel(uint8_t powerlevel)
Sets the selected transmission power level.
void SetChannelWidth(uint16_t channelWidth)
Sets the selected channelWidth (in MHz)
void SetGuardInterval(uint16_t guardInterval)
Sets the guard interval duration (in nanoseconds)
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.
void SetAggregation(bool aggregation)
Sets if PSDU contains A-MPDU.
bool IsDlMu() const
Return true if this TX vector is used for a downlink multi-user transmission.
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.
bool IsUlMu() const
Return true if this TX vector is used for an uplink multi-user transmission.
void SetSigBMode(const WifiMode &mode)
Set the MCS used for SIG-B.
bool IsMu() const
Return true if this TX vector is used for a multi-user transmission.
void SetBssColor(uint8_t color)
Set the BSS color.
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_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.
U * PeekPointer(const Ptr< U > &p)
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
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...
Ptr< T > Copy(Ptr< T > object)
Return a deep copy of a Ptr.
uint32_t GetBlockAckSize(BlockAckType type)
Return the total BlockAck size (including FCS trailer).
uint32_t GetAckSize()
Return the total Ack size (including FCS trailer).
std::unordered_map< uint16_t, Ptr< WifiPsdu > > WifiPsduMap
Map of PSDUs indexed by STA-ID.
std::vector< uint8_t > m_bitmapLen
Length (bytes) of included bitmaps.
RxSignalInfo structure containing info on the received signal.
double snr
SNR in linear scale.
WifiAcknowledgment is an abstract base struct.
Time acknowledgmentTime
time required by the acknowledgment method
const Method method
acknowledgment method
WifiDlMuAggregateTf specifies that a DL MU PPDU made of PSDUs including each a MU-BAR Trigger Frame i...
uint16_t ulLength
the UL Length field of the MU-BAR Trigger Frames
std::map< Mac48Address, BlockAckInfo > stationsReplyingWithBlockAck
Set of stations replying with a BlockAck frame.
WifiDlMuBarBaSequence specifies that a DL MU PPDU is acknowledged through a sequence of BlockAckReq a...
std::map< Mac48Address, BlockAckReqInfo > stationsSendBlockAckReqTo
Set of stations receiving a BlockAckReq frame and replying with a BlockAck frame.
std::map< Mac48Address, BlockAckInfo > stationsReplyingWithBlockAck
Set of stations replying with a BlockAck frame (no more than one)
std::map< Mac48Address, AckInfo > stationsReplyingWithNormalAck
Set of stations replying with an Ack frame (no more than one)
WifiDlMuTfMuBar specifies that a DL MU PPDU is followed after a SIFS duration by a MU-BAR Trigger Fra...
std::list< BlockAckReqType > barTypes
BAR types.
std::map< Mac48Address, BlockAckInfo > stationsReplyingWithBlockAck
Set of stations replying with a BlockAck frame.
uint16_t ulLength
the UL Length field of the MU-BAR Trigger Frame
WifiTxVector muBarTxVector
TXVECTOR used to transmit the MU-BAR Trigger Frame.
WifiNoAck specifies that no acknowledgment is required.
WifiNoProtection specifies that no protection method is used.
WifiUlMuMultiStaBa specifies that a Basic Trigger Frame is being sent to solicit TB PPDUs that will b...
BlockAckType baType
BlockAck type.
WifiTxVector tbPpduTxVector
TXVECTOR for a TB PPDU.
WifiTxVector multiStaBaTxVector
TXVECTOR for the Multi-STA BlockAck.
std::map< std::pair< Mac48Address, uint8_t >, std::size_t > stationsReceivingMultiStaBa
Map (originator, tid) pairs to the their index in baType.