16#include "ns3/ap-wifi-mac.h" 
   17#include "ns3/erp-ofdm-phy.h" 
   19#include "ns3/recipient-block-ack-agreement.h" 
   20#include "ns3/snr-tag.h" 
   21#include "ns3/sta-wifi-mac.h" 
   22#include "ns3/wifi-mac-queue.h" 
   23#include "ns3/wifi-mac-trailer.h" 
   28#undef NS_LOG_APPEND_CONTEXT 
   29#define NS_LOG_APPEND_CONTEXT WIFI_FEM_NS_LOG_APPEND_CONTEXT 
   41    return psduMap.size() == 1 && psduMap.cbegin()->first == 
SU_STA_ID &&
 
   42           psduMap.cbegin()->second->GetNMpdus() == 1 &&
 
   43           psduMap.cbegin()->second->GetHeader(0).IsTrigger();
 
 
   49    return psduMap.size() == 1 && psduMap.cbegin()->first == 
SU_STA_ID &&
 
   50           psduMap.cbegin()->second->GetNMpdus() == 1 &&
 
   51           psduMap.cbegin()->second->GetHeader(0).IsTrigger();
 
 
   58        TypeId(
"ns3::HeFrameExchangeManager")
 
   60            .AddConstructor<HeFrameExchangeManager>()
 
   62            .AddAttribute(
"ContinueTxopAfterBsrp",
 
   63                          "Whether to continue a TXOP a SIFS after the reception of responses " 
   64                          "to a BSRP Trigger Frame when TXOP limit is zero.",
 
 
   72    : m_intraBssNavEnd(0),
 
   73      m_triggerFrameInAmpdu(false)
 
 
  122                    "A Multi-User Scheduler can only be aggregated to an HE AP");
 
 
  143        (!(mpdu = edca->PeekNextMpdu(
m_linkId)) ||
 
  144         (mpdu->GetHeader().IsQosData() && !mpdu->GetHeader().GetAddr1().IsGroup() &&
 
  145          m_mac->GetBaAgreementEstablishedAsOriginator(mpdu->GetHeader().GetAddr1(),
 
  146                                                       mpdu->GetHeader().GetQosTid()))))
 
  165                "The Multi-user Scheduler returned DL_MU_TX with empty psduMap, do not transmit");
 
 
  216                                         << 
") incompatible with Basic Trigger Frame");
 
  220                                         << 
") incompatible with BSRP Trigger Frame");
 
  222        auto txVector = trigger.GetHeTbTxVector(trigger.begin()->GetAid12());
 
  239            if (mpdu->IsQueued())
 
 
  256                    "Cannot use RTS/CTS with MU PPDUs");
 
 
  273std::set<Mac48Address>
 
  276    std::set<Mac48Address> recipients;
 
  280    for (
const auto& userInfo : trigger)
 
  282        const auto addressIt = aidAddrMap.find(userInfo.GetAid12());
 
  283        NS_ASSERT_MSG(addressIt != aidAddrMap.end(), 
"AID not found");
 
  284        recipients.insert(addressIt->second);
 
 
  304                NS_LOG_INFO(
"Multi-user scheduler aborted the transmission");
 
 
  335    NS_LOG_FUNCTION(
this << muRtsSize << muRtsTxVector << txDuration << response);
 
  339    const auto singleDurationId =
 
  344        return singleDurationId;
 
 
  381    protection->muRts.SetCsRequired(
true);
 
  383    payload->AddHeader(protection->muRts);
 
  389    mpdu->GetHeader().SetDuration(
 
  391                           protection->muRtsTxVector,
 
  404                                                protection->muRtsTxVector,
 
  416                  protection->muRtsTxVector);
 
 
  442    auto it = std::find_if(
 
  445        [&to](std::pair<uint16_t, 
Ptr<WifiPsdu>> psdu) { return psdu.second->GetAddr1() == to; });
 
  446    if (it != psduMap.end())
 
 
  481        NS_LOG_DEBUG(address << 
" did not respond, hence it is no longer protected");
 
  491        NS_LOG_DEBUG(
"Schedule another transmission in a SIFS after successful BSRP TF");
 
  494            if (!StartTransmission(m_edca, Seconds(0)))
 
 
  512HeFrameExchangeManager::SendPsduMap()
 
  524    std::set<Mac48Address> staExpectResponseFrom;
 
  531    if (m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE)
 
  533        auto acknowledgment =
 
  537        for (
const auto& psdu : m_psduMap)
 
  539            if (acknowledgment->stationsSendBlockAckReqTo.contains(psdu.second->GetAddr1()))
 
  542                std::set<uint8_t> tids = psdu.second->GetTids();
 
  544                                "Acknowledgment method incompatible with a Multi-TID A-MPDU");
 
  545                uint8_t tid = *tids.begin();
 
  549                    m_mac->GetQosTxop(tid)->PrepareBlockAckRequest(psdu.second->GetAddr1(), tid);
 
  550                m_edca->GetBaManager()->ScheduleBar(reqHdr, hdr);
 
  554        if (!acknowledgment->stationsReplyingWithNormalAck.empty())
 
  557            timerType = WifiTxTimer::WAIT_NORMAL_ACK_AFTER_DL_MU_PPDU;
 
  559                &acknowledgment->stationsReplyingWithNormalAck.begin()->second.ackTxVector;
 
  560            auto from = acknowledgment->stationsReplyingWithNormalAck.begin()->first;
 
  561            psdu = GetPsduTo(from, m_psduMap);
 
  563            mpdu = *psdu->begin();
 
  564            staExpectResponseFrom.insert(from);
 
  566        else if (!acknowledgment->stationsReplyingWithBlockAck.empty())
 
  569            timerType = WifiTxTimer::WAIT_BLOCK_ACK;
 
  571                &acknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
 
  572            auto from = acknowledgment->stationsReplyingWithBlockAck.begin()->first;
 
  573            psdu = GetPsduTo(from, m_psduMap);
 
  574            staExpectResponseFrom.insert(from);
 
  581    else if (m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_TF_MU_BAR)
 
  583        auto acknowledgment = 
static_cast<WifiDlMuTfMuBar*
>(m_txParams.m_acknowledgment.get());
 
  590            std::map<uint16_t, CtrlBAckRequestHeader> recipients;
 
  592            NS_ASSERT(!acknowledgment->stationsReplyingWithBlockAck.empty());
 
  593            auto staIt = acknowledgment->stationsReplyingWithBlockAck.begin();
 
  594            m_trigVector = staIt->second.blockAckTxVector;
 
  595            while (staIt != acknowledgment->stationsReplyingWithBlockAck.end())
 
  598                uint16_t staId = m_apMac->GetAssociationId(staIt->first, m_linkId);
 
  600                m_trigVector.SetHeMuUserInfo(staId,
 
  601                                             staIt->second.blockAckTxVector.GetHeMuUserInfo(staId));
 
  602                recipients.emplace(staId, staIt->second.barHeader);
 
  608            m_trigVector.SetLength(acknowledgment->ulLength);
 
  610            m_triggerFrame = PrepareMuBar(m_trigVector, recipients);
 
  617            for (
auto& station : acknowledgment->stationsReplyingWithBlockAck)
 
  619                staExpectResponseFrom.insert(station.first);
 
  622            Ptr<WifiPsdu> triggerPsdu = GetWifiPsdu(m_triggerFrame, acknowledgment->muBarTxVector);
 
  623            Time txDuration = WifiPhy::CalculateTxDuration(triggerPsdu->GetSize(),
 
  624                                                           acknowledgment->muBarTxVector,
 
  625                                                           m_phy->GetPhyBand());
 
  627            *acknowledgment->acknowledgmentTime -= (m_phy->GetSifs() + txDuration);
 
  628            m_triggerFrame->GetHeader().SetDuration(GetPsduDurationId(txDuration, m_txParams));
 
  631                &acknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
 
  632            Time timeout = txDuration + m_phy->GetSifs() + m_phy->GetSlot() +
 
  633                           WifiPhy::CalculatePhyPreambleAndHeaderDuration(*responseTxVector);
 
  635            m_txTimer.Set(WifiTxTimer::WAIT_BLOCK_ACKS_IN_TB_PPDU,
 
  637                          staExpectResponseFrom,
 
  638                          &HeFrameExchangeManager::BlockAcksInTbPpduTimeout,
 
  641                          staExpectResponseFrom.size());
 
  642            m_channelAccessManager->NotifyAckTimeoutStartNow(
timeout);
 
  644            ForwardPsduDown(triggerPsdu, acknowledgment->muBarTxVector);
 
  649            hePhy->SetTrigVector(m_trigVector, 
timeout);
 
  657    else if (m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF)
 
  659        auto acknowledgment = 
static_cast<WifiDlMuAggregateTf*
>(m_txParams.m_acknowledgment.get());
 
  665        for (
auto& station : acknowledgment->stationsReplyingWithBlockAck)
 
  667            staExpectResponseFrom.insert(station.first);
 
  670            auto psduMapIt = std::find_if(m_psduMap.begin(),
 
  673                                              return psdu.second->GetAddr1() == station.first;
 
  678            std::vector<Ptr<WifiMpdu>> mpduList(psduMapIt->second->begin(),
 
  679                                                psduMapIt->second->end());
 
  680            NS_ASSERT(mpduList.size() == psduMapIt->second->GetNMpdus());
 
  683            station.second.blockAckTxVector.SetLength(acknowledgment->ulLength);
 
  684            mpduList.push_back(PrepareMuBar(station.second.blockAckTxVector,
 
  685                                            {{psduMapIt->first, station.second.barHeader}}));
 
  686            psduMapIt->second = Create<WifiPsdu>(std::move(mpduList));
 
  687            m_trigVector.SetHeMuUserInfo(
 
  689                station.second.blockAckTxVector.GetHeMuUserInfo(psduMapIt->first));
 
  692        timerType = WifiTxTimer::WAIT_BLOCK_ACKS_IN_TB_PPDU;
 
  694            &acknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
 
  695        m_trigVector.
SetLength(acknowledgment->ulLength);
 
  700    else if (m_txParams.m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA)
 
  704        mpdu = *m_psduMap.begin()->second->begin();
 
  706        auto acknowledgment = 
static_cast<WifiUlMuMultiStaBa*
>(m_txParams.m_acknowledgment.get());
 
  709        for (
const auto& station : acknowledgment->stationsReceivingMultiStaBa)
 
  711            staExpectResponseFrom.insert(station.first.first);
 
  717        acknowledgment->baType.m_bitmapLen.clear();
 
  719        timerType = WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF;
 
  720        responseTxVector = &acknowledgment->tbPpduTxVector;
 
  721        m_trigVector = GetTrigVector(m_muScheduler->GetUlMuInfo(m_linkId).trigger);
 
  726    else if (m_txParams.m_acknowledgment->method == WifiAcknowledgment::NONE &&
 
  727             !m_txParams.m_txVector.IsUlMu() && 
IsTrigger(m_psduMap))
 
  729        CtrlTriggerHeader& trigger = m_muScheduler->GetUlMuInfo(m_linkId).trigger;
 
  734        for (
const auto& userInfo : trigger)
 
  736            auto staIt = m_apMac->GetStaList(m_linkId).find(userInfo.GetAid12());
 
  737            NS_ASSERT(staIt != m_apMac->GetStaList(m_linkId).end());
 
  738            staExpectResponseFrom.insert(staIt->second);
 
  741        timerType = WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF;
 
  742        txVector = trigger.GetHeTbTxVector(trigger.begin()->GetAid12());
 
  743        responseTxVector = &txVector;
 
  744        m_trigVector = GetTrigVector(m_muScheduler->GetUlMuInfo(m_linkId).trigger);
 
  749    else if (m_txParams.m_txVector.IsUlMu() &&
 
  750             m_txParams.m_acknowledgment->method == WifiAcknowledgment::ACK_AFTER_TB_PPDU)
 
  753        timerType = WifiTxTimer::WAIT_BLOCK_ACK_AFTER_TB_PPDU;
 
  754        NS_ASSERT(m_staMac && m_staMac->IsAssociated());
 
  755        auto recv = m_psduMap.begin()->second->GetAddr1();
 
  756        txVector = GetWifiRemoteStationManager()->GetBlockAckTxVector(recv, m_txParams.m_txVector);
 
  757        responseTxVector = &txVector;
 
  758        staExpectResponseFrom.insert(recv);
 
  763    else if (m_txParams.m_txVector.IsUlMu() &&
 
  764             m_txParams.m_acknowledgment->method == WifiAcknowledgment::NONE)
 
  770        NS_ABORT_MSG(
"Unable to handle the selected acknowledgment method (" 
  771                     << m_txParams.m_acknowledgment.get() << 
")");
 
  776    for (
const auto& psdu : m_psduMap)
 
  778        psduMap.emplace(psdu.first, psdu.second);
 
  782    if (m_txParams.m_txVector.IsUlMu())
 
  784        txDuration = HePhy::ConvertLSigLengthToHeTbPpduDuration(m_txParams.m_txVector.GetLength(),
 
  785                                                                m_txParams.m_txVector,
 
  786                                                                m_phy->GetPhyBand());
 
  791            WifiPhy::CalculateTxDuration(psduMap, m_txParams.m_txVector, m_phy->GetPhyBand());
 
  794        Time durationId = GetPsduDurationId(txDuration, m_txParams);
 
  796        if (m_continueTxopAfterBsrpTf && m_edca && m_edca->GetTxopLimit(m_linkId).IsZero() &&
 
  797            timerType == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF)
 
  801            durationId += m_muScheduler->GetExtraTimeForBsrpTfDurationId(m_linkId);
 
  804        for (
auto& psdu : m_psduMap)
 
  806            psdu.second->SetDuration(durationId);
 
  810    if (timerType == WifiTxTimer::NOT_RUNNING)
 
  815            Simulator::Schedule(txDuration + m_phy->GetSifs(),
 
  816                                &HeFrameExchangeManager::SendPsduMap,
 
  819        else if (!m_txParams.m_txVector.IsUlMu())
 
  821            Simulator::Schedule(txDuration, &HeFrameExchangeManager::TransmissionSucceeded, 
this);
 
  826        Time timeout = txDuration + m_phy->GetSifs() + m_phy->GetSlot() +
 
  827                       WifiPhy::CalculatePhyPreambleAndHeaderDuration(*responseTxVector);
 
  828        m_channelAccessManager->NotifyAckTimeoutStartNow(
timeout);
 
  833        case WifiTxTimer::WAIT_NORMAL_ACK_AFTER_DL_MU_PPDU:
 
  835            m_txTimer.Set(timerType,
 
  837                          staExpectResponseFrom,
 
  838                          &HeFrameExchangeManager::NormalAckTimeout,
 
  841                          m_txParams.m_txVector);
 
  843        case WifiTxTimer::WAIT_BLOCK_ACK:
 
  845            m_txTimer.Set(timerType,
 
  847                          staExpectResponseFrom,
 
  848                          &HeFrameExchangeManager::BlockAckTimeout,
 
  851                          m_txParams.m_txVector);
 
  853        case WifiTxTimer::WAIT_BLOCK_ACKS_IN_TB_PPDU:
 
  854            m_txTimer.Set(timerType,
 
  856                          staExpectResponseFrom,
 
  857                          &HeFrameExchangeManager::BlockAcksInTbPpduTimeout,
 
  860                          staExpectResponseFrom.size());
 
  862        case WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF:
 
  863        case WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF:
 
  864            m_txTimer.Set(timerType,
 
  866                          staExpectResponseFrom,
 
  867                          &HeFrameExchangeManager::TbPpduTimeout,
 
  870                          staExpectResponseFrom.size());
 
  872        case WifiTxTimer::WAIT_BLOCK_ACK_AFTER_TB_PPDU:
 
  873            m_txTimer.Set(timerType,
 
  875                          staExpectResponseFrom,
 
  876                          &HeFrameExchangeManager::BlockAckAfterTbPpduTimeout,
 
  878                          m_psduMap.begin()->second,
 
  879                          m_txParams.m_txVector);
 
  888    ForwardPsduMapDown(psduMap, m_txParams.m_txVector);
 
  890    if (timerType == WifiTxTimer::WAIT_BLOCK_ACKS_IN_TB_PPDU ||
 
  891        timerType == WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF ||
 
  892        timerType == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF)
 
  895        auto hePhy = StaticCast<HePhy>(m_phy->GetPhyEntity(responseTxVector->GetModulationClass()));
 
  896        hePhy->SetTrigVector(m_trigVector, m_txTimer.GetDelayLeft());
 
  898    else if (timerType == WifiTxTimer::NOT_RUNNING &&
 
  899             (m_txParams.m_txVector.IsUlMu() ||
 
  900              m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE))
 
  904        Simulator::Schedule(txDuration, &WifiPsduMap::clear, &m_psduMap);
 
  907    if (m_txTimer.IsRunning() && timerType != WifiTxTimer::WAIT_BLOCK_ACK_AFTER_TB_PPDU)
 
  913        for (
const auto& address : staExpectResponseFrom)
 
  915            if (!GetWifiRemoteStationManager()->GetEmlsrEnabled(address) ||
 
  916                timerType == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF ||
 
  917                m_protectedStas.contains(address))
 
  919                m_sentFrameTo.insert(address);
 
 
  933        auto sigBMode = hePhy->GetSigBMode(txVector);
 
  937    for (
const auto& psdu : psduMap)
 
  939        NS_LOG_DEBUG(
"Transmitting: [STAID=" << psdu.first << 
", " << *psdu.second << 
"]");
 
  942    for (
const auto& [staId, psdu] : psduMap)
 
  944        FinalizeMacHeader(psdu);
 
  945        NotifyTxToEdca(psdu);
 
  949    if (psduMap.size() > 1 || psduMap.begin()->second->IsAggregate() ||
 
  950        psduMap.begin()->second->IsSingle())
 
  955    const auto txDuration = WifiPhy::CalculateTxDuration(psduMap, txVector, m_phy->GetPhyBand());
 
  956    SetTxNav(*psduMap.cbegin()->second->begin(), txDuration);
 
  958    m_phy->Send(psduMap, txVector);
 
 
  962HeFrameExchangeManager::PrepareMuBar(
const WifiTxVector& responseTxVector,
 
  963                                     std::map<uint16_t, CtrlBAckRequestHeader> recipients)
 const 
  970    SetTargetRssi(muBar);
 
  976    for (
auto& userInfo : muBar)
 
  978        auto recipientIt = recipients.find(userInfo.GetAid12());
 
  979        NS_ASSERT(recipientIt != recipients.end());
 
  982        userInfo.SetMuBarTriggerDepUserInfo(recipientIt->second);
 
  986    bar->AddHeader(muBar);
 
  994        rxAddress = Mac48Address::GetBroadcast();
 
  999        rxAddress = m_apMac->GetStaList(m_linkId).at(recipients.begin()->first);
 
 1011    return Create<WifiMpdu>(bar, hdr);
 
 
 1020    if (protection->
method == WifiProtection::MU_RTS_CTS)
 
 1027            GetCtsTxVectorAfterMuRts(muRtsCtsProtection->muRts,
 
 1028                                     muRtsCtsProtection->muRts.begin()->GetAid12());
 
 1031                             muRtsCtsProtection->muRts.GetSerializedSize() + WIFI_MAC_FCS_LENGTH;
 
 1032        muRtsCtsProtection->protectionTime =
 
 1033            WifiPhy::CalculateTxDuration(muRtsSize,
 
 1034                                         muRtsCtsProtection->muRtsTxVector,
 
 1035                                         m_phy->GetPhyBand()) +
 
 1036            WifiPhy::CalculateTxDuration(
GetCtsSize(), ctsTxVector, m_phy->GetPhyBand()) +
 
 1037            2 * m_phy->GetSifs();
 
 1041        VhtFrameExchangeManager::CalculateProtectionTime(protection);
 
 
 1054    if (acknowledgment->
method == WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE)
 
 1061        NS_ABORT_IF(dlMuBarBaAcknowledgment->stationsReplyingWithNormalAck.size() +
 
 1062                        dlMuBarBaAcknowledgment->stationsReplyingWithBlockAck.size() >
 
 1065        if (!dlMuBarBaAcknowledgment->stationsReplyingWithNormalAck.empty())
 
 1068                dlMuBarBaAcknowledgment->stationsReplyingWithNormalAck.begin()->second;
 
 1071                WifiPhy::CalculateTxDuration(
GetAckSize(), info.ackTxVector, m_phy->GetPhyBand());
 
 1074        if (!dlMuBarBaAcknowledgment->stationsReplyingWithBlockAck.empty())
 
 1077                dlMuBarBaAcknowledgment->stationsReplyingWithBlockAck.begin()->second;
 
 1079                m_phy->GetSifs() + WifiPhy::CalculateTxDuration(
GetBlockAckSize(info.baType),
 
 1080                                                                info.blockAckTxVector,
 
 1081                                                                m_phy->GetPhyBand());
 
 1084        for (
const auto& stations : dlMuBarBaAcknowledgment->stationsSendBlockAckReqTo)
 
 1086            const auto& info = stations.second;
 
 1087            duration += m_phy->GetSifs() +
 
 1089                                                     info.blockAckReqTxVector,
 
 1090                                                     m_phy->GetPhyBand()) +
 
 1093                                                     info.blockAckTxVector,
 
 1094                                                     m_phy->GetPhyBand());
 
 1097        dlMuBarBaAcknowledgment->acknowledgmentTime = duration;
 
 1102    else if (acknowledgment->
method == WifiAcknowledgment::DL_MU_TF_MU_BAR)
 
 1104        auto dlMuTfMuBarAcknowledgment = 
static_cast<WifiDlMuTfMuBar*
>(acknowledgment);
 
 1108        for (
const auto& stations : dlMuTfMuBarAcknowledgment->stationsReplyingWithBlockAck)
 
 1111            const auto& info = stations.second;
 
 1112            NS_ASSERT(info.blockAckTxVector.GetHeMuUserInfoMap().size() == 1);
 
 1113            uint16_t staId = info.blockAckTxVector.GetHeMuUserInfoMap().begin()->first;
 
 1115                                                                     info.blockAckTxVector,
 
 1116                                                                     m_phy->GetPhyBand(),
 
 1119            if (currBlockAckDuration > duration)
 
 1121                duration = currBlockAckDuration;
 
 1127        WifiTxVector& txVector = dlMuTfMuBarAcknowledgment->stationsReplyingWithBlockAck.begin()
 
 1128                                     ->second.blockAckTxVector;
 
 1129        std::tie(dlMuTfMuBarAcknowledgment->ulLength, duration) =
 
 1130            HePhy::ConvertHeTbPpduDurationToLSigLength(duration, txVector, m_phy->GetPhyBand());
 
 1133                                      ? TriggerFrameVariant::HE
 
 1134                                      : TriggerFrameVariant::EHT;
 
 1137                         dlMuTfMuBarAcknowledgment->muBarTxVector.GetChannelWidth(),
 
 1138                         dlMuTfMuBarAcknowledgment->barTypes);
 
 1139        if (dlMuTfMuBarAcknowledgment->muBarTxVector.GetModulationClass() >= 
WIFI_MOD_CLASS_VHT)
 
 1142            muBarSize = MpduAggregator::GetSizeIfAggregated(muBarSize, 0);
 
 1144        dlMuTfMuBarAcknowledgment->acknowledgmentTime =
 
 1146            WifiPhy::CalculateTxDuration(muBarSize,
 
 1147                                         dlMuTfMuBarAcknowledgment->muBarTxVector,
 
 1148                                         m_phy->GetPhyBand()) +
 
 1149            m_phy->GetSifs() + duration;
 
 1154    else if (acknowledgment->
method == WifiAcknowledgment::DL_MU_AGGREGATE_TF)
 
 1160        for (
const auto& stations : dlMuAggrTfAcknowledgment->stationsReplyingWithBlockAck)
 
 1163            const auto& info = stations.second;
 
 1164            NS_ASSERT(info.blockAckTxVector.GetHeMuUserInfoMap().size() == 1);
 
 1165            uint16_t staId = info.blockAckTxVector.GetHeMuUserInfoMap().begin()->first;
 
 1167                                                                     info.blockAckTxVector,
 
 1168                                                                     m_phy->GetPhyBand(),
 
 1171            if (currBlockAckDuration > duration)
 
 1173                duration = currBlockAckDuration;
 
 1180            dlMuAggrTfAcknowledgment->stationsReplyingWithBlockAck.begin()->second.blockAckTxVector;
 
 1181        std::tie(dlMuAggrTfAcknowledgment->ulLength, duration) =
 
 1182            HePhy::ConvertHeTbPpduDurationToLSigLength(duration, txVector, m_phy->GetPhyBand());
 
 1183        dlMuAggrTfAcknowledgment->acknowledgmentTime = m_phy->GetSifs() + duration;
 
 1188    else if (acknowledgment->
method == WifiAcknowledgment::UL_MU_MULTI_STA_BA)
 
 1193                                                     ulMuMultiStaBa->multiStaBaTxVector,
 
 1194                                                     m_phy->GetPhyBand());
 
 1195        ulMuMultiStaBa->acknowledgmentTime = m_phy->GetSifs() + duration;
 
 1200    else if (acknowledgment->
method == WifiAcknowledgment::ACK_AFTER_TB_PPDU)
 
 1209        VhtFrameExchangeManager::CalculateAcknowledgmentTime(acknowledgment);
 
 
 1214HeFrameExchangeManager::GetCtsModeAfterMuRts()
 const 
 1219                                                       : OfdmPhy::GetOfdmRate6Mbps();
 
 
 1224                                                 uint16_t staId)
 const 
 1229    NS_ASSERT_MSG(userInfoIt != trigger.
end(), 
"User Info field for AID=" << staId << 
" not found");
 
 1232    if (uint8_t ru = userInfoIt->GetMuRtsRuAllocation(); ru < 65)
 
 1254    auto txVector = GetWifiRemoteStationManager()->GetCtsTxVector(m_bssid, GetCtsModeAfterMuRts());
 
 1256    txVector.SetChannelWidth(bw);
 
 
 1262HeFrameExchangeManager::GetTxDuration(
uint32_t ppduPayloadSize,
 
 1268        return VhtFrameExchangeManager::GetTxDuration(ppduPayloadSize, receiver, txParams);
 
 1275        txParams.
m_acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF)
 
 1279        NS_ASSERT_MSG(psduInfo, 
"No information for " << receiver << 
" in TX params");
 
 1280        NS_ASSERT_MSG(!psduInfo->seqNumbers.empty(), 
"No sequence number for " << receiver);
 
 1281        const auto tid = psduInfo->seqNumbers.cbegin()->first;
 
 1284                                      ? TriggerFrameVariant::HE
 
 1285                                      : TriggerFrameVariant::EHT;
 
 1286        ppduPayloadSize = MpduAggregator::GetSizeIfAggregated(
 
 1289                         {m_mac->GetBarTypeAsOriginator(receiver, tid)}),
 
 1293    uint16_t staId = (txParams.
m_txVector.
IsDlMu() ? m_apMac->GetAssociationId(receiver, m_linkId)
 
 1294                                                   : m_staMac->GetAssociationId());
 
 1295    Time psduDuration = WifiPhy::CalculateTxDuration(ppduPayloadSize,
 
 1297                                                     m_phy->GetPhyBand(),
 
 
 1304HeFrameExchangeManager::TbPpduTimeout(
WifiPsduMap* psduMap, std::size_t nSolicitedStations)
 
 1307    DoTbPpduTimeout(psduMap, nSolicitedStations, 
true);
 
 
 1312                                        std::size_t nSolicitedStations,
 
 1313                                        bool updateFailedCw)
 
 1315    const auto& staMissedTbPpduFrom = m_txTimer.GetStasExpectedToRespond();
 
 1316    NS_LOG_FUNCTION(
this << psduMap << staMissedTbPpduFrom.size() << nSolicitedStations
 
 1323    NS_ASSERT(!staMissedTbPpduFrom.empty());
 
 1326    if (staMissedTbPpduFrom.size() == nSolicitedStations)
 
 1330        psduMap->cbegin()->second->GetPayload(0)->PeekHeader(trigger);
 
 1332        if (m_continueTxopAfterBsrpTf && m_edca->GetTxopLimit(m_linkId).IsZero() &&
 
 1335            SendCfEndIfNeeded();
 
 1338        TransmissionFailed(!updateFailedCw);
 
 1340    else if (!m_multiStaBaEvent.IsPending())
 
 1342        m_edca->ResetCw(m_linkId);
 
 1343        TransmissionSucceeded();
 
 1349        for (
const auto& address : staMissedTbPpduFrom)
 
 1351            NS_LOG_DEBUG(address << 
" did not respond, hence it is no longer protected");
 
 1352            m_protectedStas.erase(address);
 
 1353            m_sentFrameTo.erase(address);
 
 1355        if (m_protectedIfResponded)
 
 1357            m_protectedStas.merge(m_sentFrameTo);
 
 1359        m_sentFrameTo.clear();
 
 
 1367                                                 std::size_t nSolicitedStations)
 
 1372    NS_ASSERT(m_txParams.m_acknowledgment &&
 
 1373              (m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF ||
 
 1374               m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_TF_MU_BAR));
 
 1377    const auto& staMissedBlockAckFrom = m_txTimer.GetStasExpectedToRespond();
 
 1378    NS_ASSERT(!staMissedBlockAckFrom.empty());
 
 1380    if (staMissedBlockAckFrom.size() == nSolicitedStations)
 
 1383        GetWifiRemoteStationManager()->ReportDataFailed(*psduMap->begin()->second->begin());
 
 1389        m_triggerFrame = 
nullptr;
 
 1392    for (
const auto& sta : staMissedBlockAckFrom)
 
 1394        auto psdu = GetPsduTo(sta, *psduMap);
 
 1396        MissedBlockAck(psdu, m_txParams.m_txVector);
 
 1401    if (staMissedBlockAckFrom.size() == nSolicitedStations)
 
 1404        TransmissionFailed();
 
 1408        m_edca->ResetCw(m_linkId);
 
 1409        TransmissionSucceeded();
 
 
 1419    GetWifiRemoteStationManager()->ReportDataFailed(*psdu->begin());
 
 1421    MissedBlockAck(psdu, m_txParams.m_txVector);
 
 
 1436    VhtFrameExchangeManager::NormalAckTimeout(mpdu, txVector);
 
 1441    for (
auto& psdu : m_psduMap)
 
 1445            if (mpdu->IsQueued())
 
 1447                m_mac->GetTxopQueue(mpdu->GetQueueAc())->GetOriginal(mpdu)->GetHeader().SetRetry();
 
 1448                mpdu->ResetInFlight(m_linkId);
 
 
 1460    VhtFrameExchangeManager::BlockAckTimeout(psdu, txVector);
 
 1465    for (
auto& psdu : m_psduMap)
 
 1469            if (mpdu->IsQueued())
 
 1471                mpdu->GetHeader().SetRetry();
 
 
 1487    for (
const auto& userInfoField : trigger)
 
 1490            userInfoField.GetAid12(),
 
 1491            {userInfoField.GetRuAllocation(), userInfoField.GetUlMcs(), userInfoField.GetNss()});
 
 
 1503    uint16_t staId = m_staMac->GetAssociationId();
 
 1510    NS_ASSERT_MSG(heConfiguration, 
"This STA has to be an HE station to send an HE TB PPDU");
 
 1513    if (userInfoIt->IsUlTargetRssiMaxTxPower())
 
 1515        NS_LOG_LOGIC(
"AP requested using the max transmit power (" << m_phy->GetTxPowerEnd()
 
 1521    uint8_t powerLevel = GetWifiRemoteStationManager()->GetDefaultTxPowerLevel();
 
 1539    auto optRssi = GetMostRecentRssi(triggerSender);
 
 1545    auto reqTxPower = 
dBm_u{
static_cast<double>(userInfoIt->GetUlTargetRssi() + pathLossDb)};
 
 1548    uint8_t numPowerLevels = m_phy->GetNTxPower();
 
 1549    if (numPowerLevels > 1)
 
 1551        dBm_u step = (m_phy->GetTxPowerEnd() - m_phy->GetTxPowerStart()) / (numPowerLevels - 1);
 
 1552        powerLevel = 
static_cast<uint8_t
>(
 
 1553            ceil((reqTxPower - m_phy->GetTxPowerStart()) /
 
 1555        if (powerLevel > numPowerLevels)
 
 1557            powerLevel = numPowerLevels; 
 
 1560    if (reqTxPower > m_phy->GetPower(powerLevel))
 
 1562        NS_LOG_WARN(
"The requested power level (" << reqTxPower << 
"dBm) cannot be satisfied (max: " 
 1563                                                  << m_phy->GetTxPowerEnd() << 
"dBm)");
 
 1567                 << 
"{pathLoss=" << pathLossDb << 
"dB, reqTxPower=" << reqTxPower << 
"dBm}" 
 1569                 << 
"{powerLevel=" << +powerLevel << 
" -> " << m_phy->GetPower(powerLevel) << 
"dBm}" 
 1570                 << 
" PHY power capa " 
 1571                 << 
"{min=" << m_phy->GetTxPowerStart() << 
"dBm, max=" << m_phy->GetTxPowerEnd()
 
 1572                 << 
"dBm, levels:" << +numPowerLevels << 
"}");
 
 
 1578HeFrameExchangeManager::GetMostRecentRssi(
const Mac48Address& address)
 const 
 1580    return GetWifiRemoteStationManager()->GetMostRecentRssi(address);
 
 
 1590        m_phy->GetPower(GetWifiRemoteStationManager()->GetDefaultTxPowerLevel())));
 
 1591    for (
auto& userInfo : trigger)
 
 1593        const auto staList = m_apMac->GetStaList(m_linkId);
 
 1594        auto itAidAddr = staList.find(userInfo.GetAid12());
 
 1596        auto optRssi = GetMostRecentRssi(itAidAddr->second);
 
 1598        auto rssi = 
static_cast<int8_t>(*optRssi);
 
 1599        rssi = (rssi >= -20)
 
 1601                   : ((rssi <= -110) ? -110 : rssi); 
 
 1602        userInfo.SetUlTargetRssi(rssi);
 
 
 1611    auto txVectorCopy = txVector;
 
 1613    if (psdu->GetNMpdus() == 1 && psdu->GetHeader(0).IsTrigger())
 
 1616        psdu->GetPayload(0)->PeekHeader(trigger);
 
 1630            if (m_staMac != 
nullptr && m_staMac->IsAssociated() &&
 
 1641            psdu = Create<const WifiPsdu>(Create<Packet>(), rts);
 
 1645                GetWifiRemoteStationManager()->GetCtsTxVector(m_bssid, GetCtsModeAfterMuRts());
 
 1648    VhtFrameExchangeManager::PostProcessFrame(psdu, txVectorCopy);
 
 
 1658    if (!UlMuCsMediumIdle(trigger))
 
 1660        NS_LOG_DEBUG(
"UL MU CS indicated medium busy, cannot send CTS");
 
 1664    NS_ASSERT(m_staMac != 
nullptr && m_staMac->IsAssociated());
 
 1665    WifiTxVector ctsTxVector = GetCtsTxVectorAfterMuRts(trigger, m_staMac->GetAssociationId());
 
 1668    DoSendCtsAfterRts(muRtsHdr, ctsTxVector, muRtsSnr);
 
 
 1678              txParams.
m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
 
 1681    NS_ASSERT(!acknowledgment->stationsReceivingMultiStaBa.empty());
 
 1684    blockAck.
SetType(acknowledgment->baType);
 
 1688    for (
const auto& staInfo : acknowledgment->stationsReceivingMultiStaBa)
 
 1690        receiver = staInfo.first.first;
 
 1691        uint8_t tid = staInfo.first.second;
 
 1692        std::size_t index = staInfo.second;
 
 1694        blockAck.
SetAid11(m_apMac->GetAssociationId(receiver, m_linkId), index);
 
 1700            NS_LOG_DEBUG(
"Multi-STA Block Ack: Sending All-ack to=" << receiver);
 
 1705        if (acknowledgment->baType.m_bitmapLen.at(index) == 0)
 
 1708            NS_LOG_DEBUG(
"Multi-STA Block Ack: Sending Ack to=" << receiver);
 
 1716            auto agreement = m_mac->GetBaAgreementEstablishedAsRecipient(receiver, tid);
 
 1718            agreement->get().FillBlockAckBitmap(blockAck, index);
 
 1719            NS_LOG_DEBUG(
"Multi-STA Block Ack: Sending Block Ack with seq=" 
 1721                         << 
" tid=" << +tid);
 
 1727    hdr.
SetAddr1(acknowledgment->stationsReceivingMultiStaBa.size() == 1
 
 1729                     : Mac48Address::GetBroadcast());
 
 1735    packet->AddHeader(blockAck);
 
 1737        GetWifiPsdu(Create<WifiMpdu>(packet, hdr), acknowledgment->multiStaBaTxVector);
 
 1740                                                   acknowledgment->multiStaBaTxVector,
 
 1741                                                   m_phy->GetPhyBand());
 
 1753    const auto singleDurationId = 
Max(durationId - m_phy->GetSifs() - txDuration, 
Seconds(0));
 
 1754    if (m_edca->GetTxopLimit(m_linkId).IsZero()) 
 
 1756        psdu->SetDuration(singleDurationId);
 
 1760        auto duration = 
Max(m_edca->GetRemainingTxop(m_linkId) - txDuration, 
Seconds(0));
 
 1761        if (m_protectSingleExchange)
 
 1763            duration = std::min(duration, singleDurationId + m_singleExchangeProtectionSurplus);
 
 1765        psdu->SetDuration(duration);
 
 1768    psdu->GetPayload(0)->AddPacketTag(m_muSnrTag);
 
 1770    ForwardPsduDown(psdu, acknowledgment->multiStaBaTxVector);
 
 1774    m_edca->ResetCw(m_linkId);
 
 1776    Simulator::Schedule(txDuration, &HeFrameExchangeManager::TransmissionSucceeded, 
this);
 
 
 1785    NS_ASSERT(m_staMac && m_staMac->IsAssociated());
 
 1787    NS_LOG_DEBUG(
"Received a Trigger Frame (basic variant) soliciting a transmission");
 
 1789    if (!UlMuCsMediumIdle(trigger))
 
 1800    std::vector<uint8_t> tids;
 
 1801    uint16_t staId = m_staMac->GetAssociationId();
 
 1804    for (uint8_t i = 0; i < 4; i++)
 
 1807        tids.push_back(acIt->second.GetHighTid());
 
 1808        tids.push_back(acIt->second.GetLowTid());
 
 1820    Time ppduDuration = HePhy::ConvertLSigLengthToHeTbPpduDuration(trigger.
GetUlLength(),
 
 1822                                                                   m_phy->GetPhyBand());
 
 1824    for (
const auto& tid : tids)
 
 1828        if (!m_mac->GetBaAgreementEstablishedAsOriginator(hdr.
GetAddr2(), tid))
 
 1838        if (
auto mpdu = GetBar(edca->GetAccessCategory(), tid, hdr.
GetAddr2());
 
 1839            mpdu && TryAddMpdu(mpdu, txParams, ppduDuration))
 
 1842            psdu = Create<WifiPsdu>(mpdu, 
true);
 
 1848            GetWifiRemoteStationManager()->GetMldAddress(hdr.
GetAddr2()).value_or(hdr.
GetAddr2());
 
 1849        if (
auto mpdu = edca->PeekNextMpdu(m_linkId, tid, receiver))
 
 1851            mpdu = CreateAliasIfNeeded(mpdu);
 
 1852            if (
auto item = edca->GetNextMpdu(m_linkId, mpdu, txParams, ppduDuration, 
false))
 
 1855                std::vector<Ptr<WifiMpdu>> mpduList =
 
 1856                    m_mpduAggregator->GetNextAmpdu(item, txParams, ppduDuration);
 
 1857                psdu = (mpduList.size() > 1 ? Create<WifiPsdu>(std::move(mpduList))
 
 1858                                            : Create<WifiPsdu>(item, 
true));
 
 1866        psdu->SetDuration(hdr.
GetDuration() - m_phy->GetSifs() - ppduDuration);
 
 1867        SendPsduMapWithProtection(
WifiPsduMap{{staId, psdu}}, txParams);
 
 1872        SendQosNullFramesInTbPpdu(trigger, hdr);
 
 
 1882    NS_ASSERT(m_staMac && m_staMac->IsAssociated());
 
 1886    if (!UlMuCsMediumIdle(trigger))
 
 1892        GetWifiRemoteStationManager()->GetMldAddress(hdr.
GetAddr2()).value_or(hdr.
GetAddr2());
 
 1895    header.
SetAddr2(m_mac->GetAddress());
 
 1910    Time ppduDuration = HePhy::ConvertLSigLengthToHeTbPpduDuration(trigger.
GetUlLength(),
 
 1912                                                                   m_phy->GetPhyBand());
 
 1915    std::vector<Ptr<WifiMpdu>> mpduList;
 
 1917    for (uint8_t tid = 0; tid < 8; ++tid)
 
 1919        if (!m_mac->GetBaAgreementEstablishedAsOriginator(hdr.
GetAddr2(), tid))
 
 1921            NS_LOG_DEBUG(
"Skipping tid=" << +tid << 
" because no agreement established");
 
 1931        auto mpdu = Create<WifiMpdu>(Create<Packet>(), header);
 
 1932        mpdu = CreateAliasIfNeeded(mpdu);
 
 1934        UpdateTxDuration(header.
GetAddr1(), txParams);
 
 1945        NS_LOG_DEBUG(
"Aggregating a QoS Null frame with tid=" << +tid);
 
 1947        mpduList.push_back(mpdu);
 
 1950    if (mpduList.empty())
 
 1952        NS_LOG_DEBUG(
"Not enough time to send a QoS Null frame");
 
 1956    Ptr<WifiPsdu> psdu = (mpduList.size() > 1 ? Create<WifiPsdu>(std::move(mpduList))
 
 1957                                              : Create<WifiPsdu>(mpduList.front(), 
true));
 
 1958    uint16_t staId = m_staMac->GetAssociationId();
 
 1959    SendPsduMapWithProtection(
WifiPsduMap{{staId, psdu}}, txParams);
 
 
 1970    auto agreement = m_mac->GetBaAgreementEstablishedAsRecipient(m_bssid, tid);
 
 1974        NS_LOG_DEBUG(
"There's not a valid agreement for this BlockAckReq");
 
 1978    if (!UlMuCsMediumIdle(trigger))
 
 1984    auto txVector = GetHeTbTxVector(trigger, m_bssid);
 
 1985    SendBlockAck(*agreement, durationId, txVector, snr);
 
 
 2004    if (ra == m_bssid || ta == m_bssid || bssid == m_bssid)
 
 2012    if (hdr.
IsCtl() && ta == empty && ra == m_txopHolder)
 
 2026    if (bssid != empty && bssid != m_bssid)
 
 2034    if (bssid == empty && ta != empty && ra != empty && ta != m_bssid && ra != m_bssid)
 
 2047    const auto bssColor = m_mac->GetHeConfiguration()->m_bssColor;
 
 2050    return bssColor != 0 && bssColor == txVector.
GetBssColor();
 
 
 2056                                  const Time& surplus)
 
 2075    if (!IsIntraBssPpdu(hdr, txVector))
 
 2077        NS_LOG_DEBUG(
"PPDU not classified as intra-BSS, update the basic NAV");
 
 2078        VhtFrameExchangeManager::UpdateNav(hdr, txVector, surplus);
 
 2082    NS_LOG_DEBUG(
"PPDU classified as intra-BSS, update the intra-BSS NAV");
 
 2085    duration += surplus;
 
 2093        NS_LOG_DEBUG(
"Received CF-End, resetting the intra-BSS NAV");
 
 2094        IntraBssNavResetTimeout();
 
 2100    auto intraBssNavEnd = Simulator::Now() + duration;
 
 2101    if (intraBssNavEnd > m_intraBssNavEnd)
 
 2103        m_intraBssNavEnd = intraBssNavEnd;
 
 2104        NS_LOG_DEBUG(
"Updated intra-BSS NAV=" << m_intraBssNavEnd);
 
 2119                GetWifiRemoteStationManager()->GetCtsTxVector(addr2, txVector.
GetMode());
 
 2120            auto navResetDelay =
 
 2121                2 * m_phy->GetSifs() +
 
 2122                WifiPhy::CalculateTxDuration(
GetCtsSize(), ctsTxVector, m_phy->GetPhyBand()) +
 
 2123                WifiPhy::CalculatePhyPreambleAndHeaderDuration(ctsTxVector) + 2 * m_phy->GetSlot();
 
 2124            m_intraBssNavResetEvent.Cancel();
 
 2125            m_intraBssNavResetEvent =
 
 2126                Simulator::Schedule(navResetDelay,
 
 2127                                    &HeFrameExchangeManager::IntraBssNavResetTimeout,
 
 2131    NS_LOG_DEBUG(
"Current intra-BSS NAV=" << m_intraBssNavEnd);
 
 2133    m_channelAccessManager->NotifyNavStartNow(duration);
 
 
 2137HeFrameExchangeManager::ClearTxopHolderIfNeeded()
 
 2140    if (m_intraBssNavEnd <= Simulator::Now())
 
 2142        m_txopHolder.reset();
 
 
 2147HeFrameExchangeManager::NavResetTimeout()
 
 2150    m_navEnd = Simulator::Now();
 
 2153    Time intraBssNav = Simulator::GetDelayLeft(m_intraBssNavResetEvent);
 
 2154    m_channelAccessManager->NotifyNavResetNow(intraBssNav);
 
 
 2158HeFrameExchangeManager::IntraBssNavResetTimeout()
 
 2161    m_intraBssNavEnd = Simulator::Now();
 
 2162    ClearTxopHolderIfNeeded();
 
 2164    Time basicNav = Simulator::GetDelayLeft(m_navResetEvent);
 
 2165    m_channelAccessManager->NotifyNavResetNow(basicNav);
 
 
 2168std::optional<Mac48Address>
 
 2179        return VhtFrameExchangeManager::FindTxopHolder(hdr, txVector);
 
 2181    return std::nullopt;
 
 
 2185HeFrameExchangeManager::VirtualCsMediumIdle()
 const 
 2190    return m_navEnd <= Simulator::Now() && m_intraBssNavEnd <= Simulator::Now();
 
 
 2206    const Time now = Simulator::Now();
 
 2213    NS_ASSERT_MSG(m_staMac, 
"UL MU CS is only performed by non-AP STAs");
 
 2216                  "No User Info field for STA (" << m_self
 
 2217                                                 << 
") AID=" << m_staMac->GetAssociationId());
 
 2219    std::set<uint8_t> indices;
 
 2223        auto ctsTxVector = GetCtsTxVectorAfterMuRts(trigger, m_staMac->GetAssociationId());
 
 2224        auto bw = ctsTxVector.GetChannelWidth();
 
 2225        indices = m_phy->GetOperatingChannel().GetAll20MHzChannelIndicesInPrimary(bw);
 
 2230            m_phy->GetOperatingChannel().Get20MHzIndicesCoveringRu(userInfoIt->GetRuAllocation(),
 
 2233    return !m_channelAccessManager->GetPer20MHzBusy(indices);
 
 
 2242    NS_LOG_FUNCTION(
this << *mpdu << rxSignalInfo << txVector << inAmpdu);
 
 2245    NS_ASSERT(mpdu->GetHeader().GetAddr1().IsGroup() || mpdu->GetHeader().GetAddr1() == m_self);
 
 2249    if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
 
 2250        m_txTimer.GetReason() == WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF)
 
 2253        NS_ASSERT(m_txParams.m_acknowledgment &&
 
 2254                  m_txParams.m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
 
 2255        auto acknowledgment = 
static_cast<WifiUlMuMultiStaBa*
>(m_txParams.m_acknowledgment.get());
 
 2258        if (!m_txTimer.GetStasExpectedToRespond().contains(sender))
 
 2260            NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
 
 2266            NS_LOG_DEBUG(
"Received a BlockAckReq in a TB PPDU from " << sender);
 
 2269            mpdu->GetPacket()->PeekHeader(blockAckReq);
 
 2272            GetBaManager(tid)->NotifyGotBlockAckRequest(
 
 2273                m_mac->GetMldAddress(sender).value_or(sender),
 
 2278            acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, tid), index);
 
 2279            acknowledgment->baType.m_bitmapLen.push_back(
 
 2280                m_mac->GetBaTypeAsRecipient(sender, tid).m_bitmapLen.at(0));
 
 2282            m_muSnrTag.Set(staId, rxSignalInfo.
snr);
 
 2286            NS_LOG_DEBUG(
"Received an S-MPDU in a TB PPDU from " << sender << 
" (" << *mpdu << 
")");
 
 2289            GetBaManager(tid)->NotifyGotMpdu(mpdu);
 
 2292            acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, tid), index);
 
 2293            acknowledgment->baType.m_bitmapLen.push_back(0);
 
 2295            m_muSnrTag.Set(staId, rxSignalInfo.
snr);
 
 2304            VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
 
 2309        if (!acknowledgment->stationsReceivingMultiStaBa.empty() && !m_multiStaBaEvent.IsPending())
 
 2311            m_multiStaBaEvent = Simulator::Schedule(m_phy->GetSifs(),
 
 2312                                                    &HeFrameExchangeManager::SendMultiStaBlockAck,
 
 2314                                                    std::cref(m_txParams),
 
 2315                                                    mpdu->GetHeader().GetDuration());
 
 2319        m_txTimer.GotResponseFrom(sender);
 
 2321        if (m_txTimer.GetStasExpectedToRespond().empty())
 
 2325            m_channelAccessManager->NotifyAckTimeoutResetNow();
 
 2327            if (!m_multiStaBaEvent.IsPending())
 
 2332                m_edca->ResetCw(m_linkId);
 
 2333                TransmissionSucceeded();
 
 2341    if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
 
 2342        m_txTimer.GetReason() == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF &&
 
 2345        const auto& sender = hdr.
GetAddr2();
 
 2347        if (!m_txTimer.GetStasExpectedToRespond().contains(sender))
 
 2349            NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
 
 2354            NS_LOG_WARN(
"No QoS Null frame in the received MPDU");
 
 2358        NS_LOG_DEBUG(
"Received a QoS Null frame in a TB PPDU from " << sender);
 
 2359        ReceivedQosNullAfterBsrpTf(sender);
 
 2367        if (hdr.
IsCts() && m_txTimer.IsRunning() &&
 
 2368            m_txTimer.GetReason() == WifiTxTimer::WAIT_CTS && m_psduMap.size() == 1)
 
 2373            Mac48Address sender = m_psduMap.begin()->second->GetAddr1();
 
 2377            mpdu->GetPacket()->PeekPacketTag(tag);
 
 2378            GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
 
 2379            GetWifiRemoteStationManager()->ReportRtsOk(m_psduMap.begin()->second->GetHeader(0),
 
 2385            m_channelAccessManager->NotifyCtsTimeoutResetNow();
 
 2386            ProtectionCompleted();
 
 2388        else if (hdr.
IsCts() && m_txTimer.IsRunning() &&
 
 2389                 m_txTimer.GetReason() == WifiTxTimer::WAIT_CTS_AFTER_MU_RTS)
 
 2394            NS_LOG_DEBUG(
"Received a CTS frame in response to an MU-RTS");
 
 2397            m_channelAccessManager->NotifyCtsTimeoutResetNow();
 
 2398            ProtectionCompleted();
 
 2400        else if (hdr.
IsAck() && m_txTimer.IsRunning() &&
 
 2401                 m_txTimer.GetReason() == WifiTxTimer::WAIT_NORMAL_ACK_AFTER_DL_MU_PPDU)
 
 2405            NS_ASSERT(m_txParams.m_acknowledgment->method ==
 
 2406                      WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE);
 
 2408            auto acknowledgment =
 
 2410            NS_ASSERT(acknowledgment->stationsReplyingWithNormalAck.size() == 1);
 
 2412            uint16_t staId = m_apMac->GetAssociationId(
 
 2413                acknowledgment->stationsReplyingWithNormalAck.begin()->first,
 
 2415            auto it = m_psduMap.find(staId);
 
 2418                      acknowledgment->stationsReplyingWithNormalAck.begin()->first);
 
 2420            mpdu->GetPacket()->PeekPacketTag(tag);
 
 2421            ReceivedNormalAck(*it->second->begin(),
 
 2422                              m_txParams.m_txVector,
 
 2435                 m_txTimer.GetReason() == WifiTxTimer::WAIT_BLOCK_ACKS_IN_TB_PPDU)
 
 2438            NS_LOG_DEBUG(
"Received BlockAck in TB PPDU from=" << sender);
 
 2441            mpdu->GetPacket()->PeekPacketTag(tag);
 
 2445            mpdu->GetPacket()->PeekHeader(blockAck);
 
 2447            std::pair<uint16_t, uint16_t> ret =
 
 2448                GetBaManager(tid)->NotifyGotBlockAck(m_linkId,
 
 2450                                                     m_mac->GetMldAddress(sender).value_or(sender),
 
 2452            GetWifiRemoteStationManager()->ReportAmpduTxStatus(sender,
 
 2457                                                               m_txParams.m_txVector);
 
 2460            if (!m_txTimer.GetStasExpectedToRespond().contains(sender))
 
 2462                NS_LOG_WARN(
"Received a BlockAck from an unexpected stations: " << sender);
 
 2466            m_txTimer.GotResponseFrom(sender);
 
 2468            if (m_txTimer.GetStasExpectedToRespond().empty())
 
 2472                m_channelAccessManager->NotifyAckTimeoutResetNow();
 
 2476                    m_triggerFrame = 
nullptr;
 
 2479                m_edca->ResetCw(m_linkId);
 
 2481                TransmissionSucceeded();
 
 2484        else if (hdr.
IsBlockAck() && m_txTimer.IsRunning() &&
 
 2485                 m_txTimer.GetReason() == WifiTxTimer::WAIT_BLOCK_ACK_AFTER_TB_PPDU)
 
 2488            mpdu->GetPacket()->PeekHeader(blockAck);
 
 2491                            "A Multi-STA BlockAck is expected after a TB PPDU");
 
 2493            m_txTimer.GotResponseFrom(hdr.
GetAddr2());
 
 2495            NS_ASSERT(m_staMac && m_staMac->IsAssociated());
 
 2498                NS_LOG_DEBUG(
"The sender is not the AP we are associated with");
 
 2502            uint16_t staId = m_staMac->GetAssociationId();
 
 2505            if (indices.empty())
 
 2507                NS_LOG_DEBUG(
"No Per AID TID Info subfield intended for me");
 
 2512            mpdu->GetPacket()->PeekPacketTag(tag);
 
 2515            for (
const auto& index : indices)
 
 2522                    NS_ABORT_IF(m_psduMap.empty() || m_psduMap.begin()->first != staId);
 
 2523                    GetBaManager(tid)->NotifyGotAck(m_linkId, *m_psduMap.at(staId)->begin());
 
 2532                        NS_ABORT_IF(m_psduMap.empty() || m_psduMap.begin()->first != staId);
 
 2533                        std::set<uint8_t> tids = m_psduMap.at(staId)->GetTids();
 
 2534                        NS_ABORT_MSG_IF(tids.size() > 1, 
"Multi-TID A-MPDUs not supported yet");
 
 2535                        tid = *tids.begin();
 
 2538                    std::pair<uint16_t, uint16_t> ret = GetBaManager(tid)->NotifyGotBlockAck(
 
 2544                    GetWifiRemoteStationManager()->ReportAmpduTxStatus(hdr.
GetAddr2(),
 
 2549                                                                       m_txParams.m_txVector);
 
 2552                if (m_psduMap.at(staId)->GetHeader(0).IsQosData() &&
 
 2554                     || std::any_of(blockAck.
GetBitmap(index).begin(),
 
 2556                                    [](uint8_t b) { return b != 0; })))
 
 2558                    NS_ASSERT(m_psduMap.at(staId)->GetHeader(0).HasData());
 
 2559                    NS_ASSERT(m_psduMap.at(staId)->GetHeader(0).GetQosTid() == tid);
 
 2564                    m_mac->GetQosTxop(tid)->StartMuEdcaTimerNow(m_linkId);
 
 2570            m_channelAccessManager->NotifyAckTimeoutResetNow();
 
 2572            for (
const auto& [staId, psdu] : m_psduMap)
 
 2574                if (psdu->GetNMpdus() == 1 && psdu->GetHeader(0).IsBlockAckReq())
 
 2581        else if (hdr.
IsBlockAck() && m_txTimer.IsRunning() &&
 
 2582                 m_txTimer.GetReason() == WifiTxTimer::WAIT_BLOCK_ACK)
 
 2588            VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
 
 2601                m_triggerFrameInAmpdu = 
true;
 
 2606            mpdu->GetPacket()->PeekHeader(trigger);
 
 2617            uint16_t staId = m_staMac->GetAssociationId();
 
 2622                NS_LOG_DEBUG(
"Received MU-RTS Trigger Frame from=" << sender);
 
 2623                GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
 
 2633                m_sendCtsEvent = Simulator::Schedule(m_phy->GetSifs(),
 
 2634                                                     &HeFrameExchangeManager::SendCtsAfterMuRts,
 
 2643                NS_LOG_DEBUG(
"Received MU-BAR Trigger Frame from=" << sender);
 
 2644                GetWifiRemoteStationManager()->ReportRxOk(sender, rxSignalInfo, txVector);
 
 2652                GetBaManager(tid)->NotifyGotBlockAckRequest(
 
 2653                    m_mac->GetMldAddress(sender).value_or(sender),
 
 2657                Simulator::Schedule(m_phy->GetSifs(),
 
 2658                                    &HeFrameExchangeManager::ReceiveMuBarTrigger,
 
 2667                Simulator::Schedule(m_phy->GetSifs(),
 
 2668                                    &HeFrameExchangeManager::ReceiveBasicTrigger,
 
 2673            else if (trigger.
IsBsrp())
 
 2675                Simulator::Schedule(m_phy->GetSifs(),
 
 2676                                    &HeFrameExchangeManager::SendQosNullFramesInTbPpdu,
 
 2685            VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
 
 2693    VhtFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
 
 
 2701                                        const std::vector<bool>& perMpduStatus)
 
 2703    std::set<uint8_t> tids = psdu->GetTids();
 
 2705    if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
 
 2706        m_txTimer.GetReason() == WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF)
 
 2709        NS_ASSERT(m_txParams.m_acknowledgment &&
 
 2710                  m_txParams.m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
 
 2711        auto acknowledgment = 
static_cast<WifiUlMuMultiStaBa*
>(m_txParams.m_acknowledgment.get());
 
 2714        if (!m_txTimer.GetStasExpectedToRespond().contains(sender))
 
 2716            NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
 
 2720        NS_LOG_DEBUG(
"Received an A-MPDU in a TB PPDU from " << sender << 
" (" << *psdu << 
")");
 
 2722        if (std::any_of(tids.begin(), tids.end(), [&psdu](uint8_t tid) {
 
 2723                return psdu->GetAckPolicyForTid(tid) == WifiMacHeader::NORMAL_ACK;
 
 2726            if (std::all_of(perMpduStatus.cbegin(), perMpduStatus.cend(), [](
bool v) { return v; }))
 
 2729                acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, 14),
 
 2731                acknowledgment->baType.m_bitmapLen.push_back(0);
 
 2737                for (
const auto& tid : tids)
 
 2739                    acknowledgment->stationsReceivingMultiStaBa.emplace(std::make_pair(sender, tid),
 
 2741                    acknowledgment->baType.m_bitmapLen.push_back(
 
 2742                        m_mac->GetBaTypeAsRecipient(sender, tid).m_bitmapLen.at(0));
 
 2746            m_muSnrTag.Set(staId, rxSignalInfo.
snr);
 
 2750        if (!acknowledgment->stationsReceivingMultiStaBa.empty() && !m_multiStaBaEvent.IsPending())
 
 2752            m_multiStaBaEvent = Simulator::Schedule(m_phy->GetSifs(),
 
 2753                                                    &HeFrameExchangeManager::SendMultiStaBlockAck,
 
 2755                                                    std::cref(m_txParams),
 
 2756                                                    psdu->GetDuration());
 
 2760        m_txTimer.GotResponseFrom(sender);
 
 2762        if (m_txTimer.GetStasExpectedToRespond().empty())
 
 2766            m_channelAccessManager->NotifyAckTimeoutResetNow();
 
 2768            if (!m_multiStaBaEvent.IsPending())
 
 2773                m_edca->ResetCw(m_linkId);
 
 2774                TransmissionSucceeded();
 
 2782    if (txVector.
IsUlMu() && m_txTimer.IsRunning() &&
 
 2783        m_txTimer.GetReason() == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF)
 
 2787        if (!m_txTimer.GetStasExpectedToRespond().contains(sender))
 
 2789            NS_LOG_WARN(
"Received a TB PPDU from an unexpected station: " << sender);
 
 2792        if (std::none_of(psdu->begin(), psdu->end(), [](
Ptr<WifiMpdu> mpdu) {
 
 2793                return mpdu->GetHeader().IsQosData() && !mpdu->GetHeader().HasData();
 
 2796            NS_LOG_WARN(
"No QoS Null frame in the received PSDU");
 
 2800        NS_LOG_DEBUG(
"Received QoS Null frames in a TB PPDU from " << sender);
 
 2801        ReceivedQosNullAfterBsrpTf(sender);
 
 2807    if (m_triggerFrameInAmpdu)
 
 2810        auto psduIt = psdu->begin();
 
 2811        while (psduIt != psdu->end())
 
 2813            if ((*psduIt)->GetHeader().IsTrigger())
 
 2815                ReceiveMpdu(*psduIt, rxSignalInfo, txVector, 
false);
 
 2820        m_triggerFrameInAmpdu = 
false;
 
 2825    VhtFrameExchangeManager::EndReceiveAmpdu(psdu, rxSignalInfo, txVector, perMpduStatus);
 
 
 2834              m_txTimer.GetReason() == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF);
 
 2837    m_txTimer.GotResponseFrom(sender);
 
 2839    if (m_txTimer.GetStasExpectedToRespond().empty())
 
 2842        m_channelAccessManager->NotifyAckTimeoutResetNow();
 
 2846        m_edca->ResetCw(m_linkId);
 
 2847        TransmissionSucceeded();
 
 
AttributeValue implementation for Boolean.
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
bool IsPending() 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)
uint8_t m_linkId
the ID of the link this object is associated with
Ptr< WifiMac > m_mac
the MAC layer on this station
bool m_protectedIfResponded
whether a STA is assumed to be protected if replied to a frame requiring acknowledgment
virtual void Reset()
Reset this frame exchange manager.
Mac48Address m_self
the MAC address of this device
virtual void StartProtection(const WifiTxParameters &txParams)
Start the protection mechanism indicated by the given TX parameters.
WifiTxTimer m_txTimer
the timer set upon frame transmission
std::set< Mac48Address > m_protectedStas
STAs that have replied to an RTS in this TXOP.
virtual Time GetRtsDurationId(const WifiTxVector &rtsTxVector, Time txDuration, Time response) const
Compute how to set the Duration/ID field of an RTS frame to send to protect a frame transmitted with ...
virtual void ProtectionCompleted()
Transmit prepared frame immediately, if no protection was used, or in a SIFS, if protection was compl...
virtual void NotifyChannelReleased(Ptr< Txop > txop)
Notify the given Txop that channel has been released.
virtual void CtsTimeout(Ptr< WifiMpdu > rts, const WifiTxVector &txVector)
Called when the CTS timeout expires.
void DoCtsTimeout(const WifiPsduMap &psduMap)
Take required actions when the CTS timer fired after sending an (MU-)RTS to protect the given PSDU ma...
Time m_txNav
the TXNAV timer
virtual void TransmissionSucceeded()
Take necessary actions upon a transmission success.
Ptr< WifiPhy > m_phy
the PHY layer on this station
std::set< Mac48Address > m_sentFrameTo
the STA(s) to which we sent a frame requesting a response
Ptr< ApWifiMac > m_apMac
AP MAC layer pointer (null if not an AP)
Ptr< ChannelAccessManager > m_channelAccessManager
the channel access manager
MHz_u m_allowedWidth
the allowed width for the current transmission
Ptr< StaWifiMac > m_staMac
STA MAC layer pointer (null if not a STA)
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...
void DoDispose() override
Destructor implementation.
void Reset() override
Reset this frame exchange manager.
WifiMode GetCtsModeAfterMuRts() const
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 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.
void SetMultiUserScheduler(const Ptr< MultiUserScheduler > muScheduler)
Set the Multi-user Scheduler associated with this Frame Exchange Manager.
WifiTxVector GetCtsTxVectorAfterMuRts(const CtrlTriggerHeader &trigger, uint16_t staId) const
Get the TXVECTOR that the station having the given station ID has to use to send a CTS frame after re...
bool m_continueTxopAfterBsrpTf
whether to continue a TXOP a SIFS after the reception of responses to a BSRP TF when TXOP limit is ze...
Ptr< MultiUserScheduler > m_muScheduler
Multi-user Scheduler (HE APs only)
virtual void CtsAfterMuRtsTimeout(Ptr< WifiMpdu > muRts, const WifiTxVector &txVector)
Called when no CTS frame is received after an MU-RTS.
void ProtectionCompleted() override
Transmit prepared frame immediately, if no protection was used, or in a SIFS, if protection was compl...
static Ptr< WifiPsdu > GetPsduTo(Mac48Address to, const WifiPsduMap &psduMap)
Get the PSDU in the given PSDU map that is addressed to the given MAC address, if any,...
void CtsTimeout(Ptr< WifiMpdu > rts, const WifiTxVector &txVector) override
Called when the CTS timeout expires.
EventId m_intraBssNavResetEvent
the event to reset the intra-BSS NAV after an RTS
bool StartFrameExchange(Ptr< QosTxop > edca, Time availableTime, bool initialFrame) override
Start a frame exchange (including protection frames and acknowledgment frames as needed) that fits wi...
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.
Time m_intraBssNavEnd
intra-BSS NAV expiration time
std::set< Mac48Address > GetTfRecipients(const CtrlTriggerHeader &trigger) const
Get the (link) address of the non-AP stations solicited by the given Trigger Frame.
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)
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.
void ForwardMpduDown(Ptr< WifiMpdu > mpdu, WifiTxVector &txVector) override
Forward an MPDU down to the PHY layer.
bool StartFrameExchange(Ptr< QosTxop > edca, Time availableTime, bool initialFrame) override
Start a frame exchange (including protection frames and acknowledgment frames as needed) that fits wi...
static Mac48Address GetBroadcast()
A tag to be attached to a response to a multi-user UL frame, that carries the SNR values with which t...
double Get(uint16_t staId) const
Return the SNR value for the given sender.
TxFormat
Enumeration of the possible transmission formats.
virtual void DoDispose()
Destructor implementation.
Smart pointer class similar to boost::intrusive_ptr.
Ptr< QosTxop > m_edca
the EDCAF that gained channel access
virtual bool SendCfEndIfNeeded()
Send a CF-End frame to indicate the completion of the TXOP, provided that the remaining duration is l...
Time m_singleExchangeProtectionSurplus
additional time to protect beyond end of the immediate frame exchange in case of non-zero TXOP limit ...
bool m_protectSingleExchange
true if the Duration/ID field in frames establishing protection only covers the immediate frame excha...
virtual Time GetRemainingTxop(uint8_t linkId) const
Return the remaining duration in the current TXOP on the given link.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
static Time Now()
Return the current simulation virtual time.
Introspection did not find any typical Config paths.
double Get() const
Return the SNR value.
Simulation virtual time values and global simulation resolution.
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
bool IsStrictlyPositive() const
Exactly equivalent to t > 0.
bool IsZero() const
Exactly equivalent to t == 0.
Time GetTxopLimit() const
Return the TXOP limit.
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.
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.
static Time CalculatePhyPreambleAndHeaderDuration(const WifiTxVector &txVector)
This class stores the TX parameters (TX vector, protection mechanism, acknowledgment mechanism,...
std::optional< Time > m_txDuration
TX duration of the frame.
std::unique_ptr< WifiProtection > m_protection
protection method
uint32_t GetSize(Mac48Address receiver) const
Get the size in bytes of the (A-)MPDU addressed to the given receiver.
std::unique_ptr< WifiAcknowledgment > m_acknowledgment
acknowledgment method
const PsduInfo * GetPsduInfo(Mac48Address receiver) const
Get a pointer to the information about the PSDU addressed to the given receiver, if present,...
void UndoAddMpdu()
Undo the addition of the last MPDU added by calling AddMpdu().
WifiTxVector m_txVector
TXVECTOR of the frame being prepared.
void AddMpdu(Ptr< const WifiMpdu > mpdu)
Record that an MPDU is being added to the current frame.
void Clear()
Reset the TX parameters.
bool IsRunning() const
Return true if the timer is running.
Reason
The reason why the timer was started.
@ WAIT_QOS_NULL_AFTER_BSRP_TF
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.
Reason GetReason() const
Get the reason why the timer was started.
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
void SetTxPowerLevel(uint8_t powerlevel)
Sets the selected transmission power level.
uint8_t GetBssColor() const
Get the BSS color.
void SetGuardInterval(Time guardInterval)
Sets the guard interval duration (in nanoseconds)
void SetTriggerResponding(bool triggerResponding)
Set the Trigger Responding parameter to the given value.
WifiMode GetMode(uint16_t staId=SU_STA_ID) const
If this TX vector is associated with an SU PPDU, return the selected payload transmission mode.
void SetHeMuUserInfo(uint16_t staId, HeMuUserInfo userInfo)
Set the HE MU user-specific transmission information for the given STA-ID.
WifiPreamble GetPreambleType() const
void SetAggregation(bool aggregation)
Sets if PSDU contains A-MPDU.
void SetChannelWidth(MHz_u channelWidth)
Sets the selected channelWidth.
const HeMuUserInfoMap & GetHeMuUserInfoMap() const
Get a const reference to the map HE MU user-specific transmission information indexed by STA-ID.
WifiModulationClass GetModulationClass() const
Get the modulation class specified by this TXVECTOR.
void SetLength(uint16_t length)
Set the LENGTH field of the L-SIG.
MHz_u GetChannelWidth() const
void SetSigBMode(const WifiMode &mode)
Set the MCS used for SIG-B.
void SetBssColor(uint8_t color)
Set the BSS color.
void SetMode(WifiMode mode)
Sets the selected payload transmission mode.
void SetPreambleType(WifiPreamble preamble)
Sets the preamble type.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Ptr< const AttributeChecker > MakeBooleanChecker()
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
#define NS_ABORT_IF(cond)
Abnormal program termination if a condition is true.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_WARN(msg)
Use NS_LOG to output a message of level LOG_WARN.
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Time Seconds(double value)
Construct a Time in the indicated unit.
AcIndex
This enumeration defines the Access Categories as an enumeration with values corresponding to the AC ...
@ WIFI_PHY_BAND_2_4GHZ
The 2.4 GHz band.
@ WIFI_MOD_CLASS_VHT
VHT (Clause 22)
@ WIFI_MOD_CLASS_HE
HE (Clause 27)
Declaration of ns3::HePhy class and ns3::HeSigAParameters struct.
void(* Time)(Time oldValue, Time newValue)
TracedValue callback signature for Time.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
uint32_t GetMuBarSize(TriggerFrameVariant variant, MHz_u bw, const std::list< BlockAckReqType > &types)
Return the total MU-BAR size (including FCS trailer).
U * PeekPointer(const Ptr< U > &p)
bool IsTrigger(const WifiPsduMap &psduMap)
std::unordered_map< uint16_t, Ptr< WifiPsdu > > WifiPsduMap
Map of PSDUs indexed by STA-ID.
uint32_t GetBlockAckRequestSize(BlockAckReqType type)
Return the total BlockAckRequest size (including FCS trailer).
const std::map< AcIndex, WifiAc > wifiAcList
Map containing the four ACs in increasing order of priority (according to Table 10-1 "UP-to-AC Mappin...
uint32_t GetBlockAckSize(BlockAckType type)
Return the total BlockAck size (including FCS trailer).
bool IsDlMu(WifiPreamble preamble)
Return true if a preamble corresponds to a downlink multi-user transmission.
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
uint32_t GetAckSize()
Return the total Ack size (including FCS trailer).
static constexpr uint16_t SU_STA_ID
STA_ID to identify a single user (SU)
uint32_t GetCtsSize()
Return the total CTS size (including FCS trailer).
std::vector< uint8_t > m_bitmapLen
Length (bytes) of included bitmaps.
RxSignalInfo structure containing info on the received signal.
double snr
SNR in linear scale.
WifiAcknowledgment is an abstract base struct.
const Method method
acknowledgment method
std::optional< Time > acknowledgmentTime
time required by the acknowledgment method
WifiDlMuAggregateTf specifies that a DL MU PPDU made of PSDUs including each a MU-BAR Trigger Frame i...
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.