16#include "ns3/ap-wifi-mac.h"
18#include "ns3/mgt-action-headers.h"
19#include "ns3/spectrum-signal-parameters.h"
20#include "ns3/sta-wifi-mac.h"
21#include "ns3/wifi-mac-queue.h"
22#include "ns3/wifi-net-device.h"
23#include "ns3/wifi-spectrum-phy-interface.h"
27#undef NS_LOG_APPEND_CONTEXT
28#define NS_LOG_APPEND_CONTEXT WIFI_FEM_NS_LOG_APPEND_CONTEXT
56 static TypeId tid =
TypeId(
"ns3::EhtFrameExchangeManager")
58 .AddConstructor<EhtFrameExchangeManager>()
59 .SetGroupName(
"Wifi");
95 protectionManager->SetLinkId(linkId);
99 ackManager->SetLinkId(linkId);
113 !mpdu->GetHeader().IsQosData() ||
115 mpdu->GetHeader().GetAddr1().IsGroup() ||
122 auto& hdr = mpdu->GetHeader();
126 hdr.SetAddr1(*address);
134 if (hdr.IsQosAmsdu())
136 if (hdr.IsToDs() && !hdr.IsFromDs())
139 hdr.SetAddr3(hdr.GetAddr1());
141 else if (!hdr.IsToDs() && hdr.IsFromDs())
144 hdr.SetAddr3(hdr.GetAddr2());
158 return m_staMac->GetMacQueueScheduler()->GetAllQueuesBlockedOnLink(
172 for (uint8_t linkId = 0; linkId <
m_apMac->GetNLinks(); linkId++)
180 std::set<Mac48Address> emlsrClients;
185 if (ehtFem->m_ongoingTxopEnd.IsPending() && ehtFem->m_txopHolder &&
186 m_mac->GetWifiRemoteStationManager(linkId)->GetEmlsrEnabled(
187 ehtFem->m_txopHolder.value()))
189 NS_LOG_DEBUG(
"Involved in UL TXOP: " << ehtFem->m_txopHolder.value());
190 emlsrClients.insert(ehtFem->m_txopHolder.value());
194 for (
const auto& address : ehtFem->m_protectedStas)
196 if (
m_mac->GetWifiRemoteStationManager(linkId)->GetEmlsrEnabled(address))
199 emlsrClients.insert(address);
203 for (
const auto& address : emlsrClients)
206 m_mac->GetWifiRemoteStationManager(linkId)->GetMldAddress(address);
207 NS_ASSERT_MSG(mldAddress,
"MLD address not found for " << address);
223 "No mask for client " << *mldAddress <<
" on link " << +
m_linkId);
228 "Transmissions to " << *mldAddress <<
" on link " << +
m_linkId
229 <<
" are not blocked");
245 NS_LOG_DEBUG(
"StartTransmission called while another EMLSR link is being used");
250 auto emlsrManager =
m_staMac->GetEmlsrManager();
252 if (
auto elapsed = emlsrManager->GetElapsedMediumSyncDelayTimer(
m_linkId);
253 elapsed && emlsrManager->MediumSyncDelayNTxopsExceeded(
m_linkId))
255 NS_LOG_DEBUG(
"No new TXOP attempts allowed while MediumSyncDelay is running");
259 emlsrManager->GetMediumSyncDuration() - *elapsed,
278 if (
const auto [startTxop, delay] = emlsrManager->GetDelayUntilAccessRequest(
284 if (delay.IsStrictlyPositive())
340 auto sigBMode = phy->GetSigBMode(txVector);
346 if (
m_apMac && psdu->GetHeader(0).IsTrigger())
358 for (uint8_t linkId = 0; linkId <
m_apMac->GetNLinks(); ++linkId)
361 m_mac->GetWifiRemoteStationManager(linkId)->GetEmlsrEnabled(*clientMld))
372 psdu->GetHeader(0).IsRts())
383 auto delay =
m_apMac->GetApEmlsrManager()->GetDelayOnTxPsduNotForEmlsr(psdu,
406 m_staMac->GetEmlsrManager()->GetInDeviceInterference())
409 m_staMac->GetEmlsrManager()->NotifyInDeviceInterferenceStart(
m_linkId, txDuration);
430 psduMap.cbegin()->second->GetPayload(0)->PeekHeader(trigger);
435 for (
const auto& client : recipients)
445 for (uint8_t linkId = 0; linkId <
m_apMac->GetNLinks(); ++linkId)
448 m_mac->GetWifiRemoteStationManager(linkId)->GetEmlsrEnabled(*clientMld))
450 m_mac->BlockUnicastTxOnLinks(
465 const auto psduMapIt = psduMap.find(aid);
466 const auto aidNotFoundAndNotTf = (psduMapIt == psduMap.cend()) && !
IsTrigger(psduMap);
468 const auto psdu = (psduMapIt != psduMap.cend() ? psduMapIt : psduMap.cbegin())->
second;
484 m_staMac->GetEmlsrManager()->GetInDeviceInterference())
487 m_staMac->GetEmlsrManager()->NotifyInDeviceInterferenceStart(
m_linkId, txDuration);
501 for (
const auto& phy :
m_staMac->GetDevice()->GetPhys())
507 if (
auto id =
m_staMac->GetLinkForPhy(phy);
510 const auto txPower = phy->GetPower(txVector.
GetTxPowerLevel()) + phy->GetTxGain();
534 for (
const auto& [range, interface] : rxPhy->GetSpectrumPhyInterfaces())
536 if (!interface->GetRxSpectrumModel())
548 spectrumSignalParams->duration = duration;
549 spectrumSignalParams->txPhy = txPhy->GetCurrentInterface();
550 spectrumSignalParams->txAntenna = txPhy->GetAntenna();
551 spectrumSignalParams->psd = psd;
553 rxPhy->StartRx(spectrumSignalParams, interface);
587 NS_ASSERT_MSG(mldAddress,
"MLD address not found for " << address);
589 std::set<uint8_t> linkIds{
m_linkId};
618 for (uint8_t linkId = 0; linkId <
m_apMac->GetNLinks(); ++linkId)
620 if (!
m_mac->GetWifiRemoteStationManager(linkId)->GetEmlsrEnabled(*mldAddress))
627 if (ehtFem->m_ongoingTxopEnd.IsPending() && ehtFem->m_txopHolder &&
628 m_mac->GetWifiRemoteStationManager(linkId)->GetMldAddress(*ehtFem->m_txopHolder) ==
631 NS_LOG_DEBUG(
"EMLSR client " << *mldAddress <<
" is the holder of an UL TXOP on link "
632 << +linkId <<
", do not unblock links");
636 if (linkId ==
m_linkId && !checkThisLink)
641 linkIds.insert(linkId);
644 m_apMac->GetWifiRemoteStationManager(linkId)->GetAffiliatedStaAddress(*mldAddress);
646 (ehtFem->m_sentRtsTo.contains(*linkAddr) || ehtFem->m_sentFrameTo.contains(*linkAddr) ||
647 ehtFem->m_protectedStas.contains(*linkAddr)))
650 <<
" has been sent an ICF, do not unblock links");
668 NS_ASSERT_MSG(mldAddress,
"MLD address not found for " << address);
671 auto blockLinks = [=,
this](
bool checkThisLink) {
674 NS_LOG_DEBUG(
"Could not unblock transmissions to " << address);
679 std::set<uint8_t> linkIds;
680 for (uint8_t linkId = 0; linkId <
m_mac->GetNLinks(); linkId++)
682 if (
m_mac->GetWifiRemoteStationManager(linkId)->GetEmlsrEnabled(*mldAddress))
684 linkIds.insert(linkId);
693 auto unblockLinks = [=,
this]() {
703 emlCapabilities->get().emlsrTransitionDelay);
705 endDelay.IsZero() ? unblockLinks()
718 delay.
IsZero() ? blockLinks(
false)
742 m_staMac->NotifySwitchingEmlsrLink(phy, linkId, delay);
759 const auto sequence =
m_txMiddle->GetNextSequenceNumberFor(&hdr);
768 packet->AddHeader(frame);
769 packet->AddHeader(actionHdr);
793 for (uint8_t linkId = 0; linkId <
m_mac->GetNLinks(); linkId++)
795 std::optional<Mac48Address> linkAddress;
797 (linkAddress =
m_mac->GetWifiRemoteStationManager(linkId)->GetAffiliatedStaAddress(
799 (optRssi =
m_mac->GetWifiRemoteStationManager(linkId)->GetMostRecentRssi(*linkAddress)))
821 uint8_t maxPaddingDelay = 0;
822 bool isUnprotectedEmlsrDst =
false;
824 for (
const auto& address : recipients)
832 isUnprotectedEmlsrDst =
true;
835 maxPaddingDelay = std::max(maxPaddingDelay, emlCapabilities->get().emlsrPaddingDelay);
838 if (isUnprotectedEmlsrDst)
847 if (maxPaddingDelay > 0)
851 std::size_t nDbps = rate / 1e6 * 4;
876 auto mainPhy =
m_staMac->GetDevice()->GetPhy(
m_staMac->GetEmlsrManager()->GetMainPhyId());
885 if (mainPhy->IsStateSwitching() ||
m_mac->GetLinkForPhy(mainPhy) !=
m_linkId)
887 NS_LOG_DEBUG(
"Main PHY is switching or operating on another link, abort ICF response");
926 for (
const auto& address : clients)
954 if (
const auto apEmlsrManager =
m_apMac->GetApEmlsrManager();
957 return apEmlsrManager->UpdateCwAfterFailedIcf();
971 if (
const auto apEmlsrManager =
m_apMac->GetApEmlsrManager();
974 return apEmlsrManager->ReportFailedIcf();
989 if (staMissedTbPpduFrom.size() != nSolicitedStations)
996 const auto apEmlsrManager =
m_apMac->GetApEmlsrManager();
997 const auto updateFailedCw =
998 crossLinkCollision && apEmlsrManager ? apEmlsrManager->UpdateCwAfterFailedIcf() :
true;
1004 std::size_t nSolicitedStations)
1010 if (staMissedTbPpduFrom.size() != nSolicitedStations)
1022 const std::set<Mac48Address>& staMissedResponseFrom)
const
1028 auto crossLinkCollision =
true;
1033 for (
const auto& address : staMissedResponseFrom)
1037 crossLinkCollision =
false;
1044 std::set<uint8_t> linkIds;
1045 for (uint8_t linkId = 0; linkId <
m_apMac->GetNLinks(); linkId++)
1047 if (
m_mac->GetWifiRemoteStationManager(linkId)->GetEmlsrEnabled(*mldAddress) &&
1050 linkIds.insert(linkId);
1054 if (std::any_of(linkIds.cbegin(),
1057 [=,
this](uint8_t
id) {
1058 auto ehtFem = StaticCast<EhtFrameExchangeManager>(
1059 m_mac->GetFrameExchangeManager(id));
1060 return ehtFem->m_ongoingTxopEnd.IsPending() && ehtFem->m_txopHolder &&
1061 m_mac->GetMldAddress(ehtFem->m_txopHolder.value()) == mldAddress;
1071 if (std::none_of(linkIds.cbegin(),
1075 [=,
this](uint8_t
id) {
1076 auto macHdr = m_mac->GetFrameExchangeManager(id)->GetReceivedMacHdr();
1077 if (!macHdr.has_value())
1081 auto addr2 = macHdr->get().GetAddr2();
1082 return m_mac->GetMldAddress(addr2) == mldAddress;
1085 crossLinkCollision =
false;
1089 return crossLinkCollision;
1101 if (m_apMac && GetWifiRemoteStationManager()->GetEmlsrEnabled(addr2))
1106 auto mldAddress = GetWifiRemoteStationManager()->GetMldAddress(addr2);
1107 NS_ASSERT_MSG(mldAddress,
"MLD address not found for " << addr2);
1109 for (uint8_t linkId = 0; linkId < m_apMac->GetNLinks(); ++linkId)
1111 if (linkId != m_linkId &&
1112 m_mac->GetWifiRemoteStationManager(linkId)->GetEmlsrEnabled(*mldAddress))
1116 WifiRcvAddr::UNICAST,
1120 m_apMac->GetMacQueueScheduler()->GetQueueLinkMask(
AC_BE, queueId, linkId);
1121 NS_ASSERT_MSG(mask,
"No mask for client " << *mldAddress <<
" on link " << +linkId);
1123 static_cast<std::size_t
>(WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK)))
1126 "Transmissions to " << *mldAddress <<
" on link " << +linkId
1127 <<
" are not blocked");
1130 m_mac->BlockUnicastTxOnLinks(WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1138 HeFrameExchangeManager::SendCtsAfterRts(rtsHdr, rtsTxVector, rtsSnr);
1154 if (psdu->GetAddr1() == address)
1163 if (mpdu->GetHeader().IsTrigger())
1166 mpdu->GetPacket()->PeekHeader(trigger);
1176 if (psdu->GetHeader(0).IsCts())
1178 if (m_apMac && psdu->GetAddr1() == m_self)
1182 if (m_staMac && psdu->GetAddr1() == m_bssid)
1190 if (psdu->GetHeader(0).IsBlockAck())
1193 psdu->GetPayload(0)->PeekHeader(blockAck);
1208EhtFrameExchangeManager::TransmissionSucceeded()
1212 if (m_staMac && m_staMac->IsEmlsrLink(m_linkId) &&
1213 m_staMac->GetEmlsrManager()->GetElapsedMediumSyncDelayTimer(m_linkId))
1215 NS_LOG_DEBUG(
"Reset the counter of TXOP attempts allowed while "
1216 "MediumSyncDelay is running");
1217 m_staMac->GetEmlsrManager()->ResetMediumSyncDelayNTxops(m_linkId);
1220 HeFrameExchangeManager::TransmissionSucceeded();
1224EhtFrameExchangeManager::TransmissionFailed(
bool forceCurrentCw)
1228 if (m_staMac && m_staMac->IsEmlsrLink(m_linkId) &&
1229 m_staMac->GetEmlsrManager()->GetElapsedMediumSyncDelayTimer(m_linkId))
1231 NS_LOG_DEBUG(
"Decrement the remaining number of TXOP attempts allowed while "
1232 "MediumSyncDelay is running");
1233 m_staMac->GetEmlsrManager()->DecrementMediumSyncDelayNTxops(m_linkId);
1236 HeFrameExchangeManager::TransmissionFailed(forceCurrentCw);
1240EhtFrameExchangeManager::NotifyChannelReleased(
Ptr<Txop> txop)
1251 if (
const auto remTxNav = m_txNav - Simulator::Now(); remTxNav.IsStrictlyPositive())
1256 for (
const auto& address : m_protectedStas)
1258 if (GetWifiRemoteStationManager()->GetEmlsrEnabled(address))
1260 EmlsrSwitchToListening(address, delay);
1264 else if (m_staMac && m_staMac->IsEmlsrLink(m_linkId))
1267 auto edca = DynamicCast<QosTxop>(txop);
1271 m_staMac->GetEmlsrManager()->NotifyTxopEnd(m_linkId, edca);
1274 HeFrameExchangeManager::NotifyChannelReleased(txop);
1285 if (m_staMac && m_staMac->IsEmlsrLink(m_linkId) &&
1286 m_staMac->GetEmlsrManager()->GetElapsedMediumSyncDelayTimer(m_linkId))
1288 m_staMac->GetEmlsrManager()->CancelMediumSyncDelayTimer(m_linkId);
1300 for (
auto clientIt = m_protectedStas.begin(); clientIt != m_protectedStas.end();)
1309 if (GetWifiRemoteStationManager()->GetEmlsrEnabled(*clientIt) && !txVector.
IsUlMu() &&
1310 !m_txTimer.GetStasExpectedToRespond().contains(*clientIt))
1312 EmlsrSwitchToListening(*clientIt,
Seconds(0));
1314 clientIt = m_protectedStas.erase(clientIt);
1323 HeFrameExchangeManager::PreProcessFrame(psdu, txVector);
1331 HeFrameExchangeManager::PostProcessFrame(psdu, txVector);
1333 if (m_apMac && m_apMac->GetApEmlsrManager())
1335 m_apMac->GetApEmlsrManager()->NotifyPsduRxOk(m_linkId, psdu);
1338 if (m_apMac && m_txopHolder == psdu->GetAddr2() &&
1339 GetWifiRemoteStationManager()->GetEmlsrEnabled(*m_txopHolder))
1341 const auto unrespondedRts = (psdu->GetHeader(0).IsRts() && !m_sendCtsEvent.IsPending());
1343 if (!m_ongoingTxopEnd.IsPending() && !unrespondedRts)
1348 Simulator::ScheduleNow(&EhtFrameExchangeManager::TxopEnd,
this, m_txopHolder);
1351 UpdateTxopEndOnRxEnd(psdu->GetDuration());
1354 if (m_staMac && m_ongoingTxopEnd.IsPending())
1356 if (GetEmlsrSwitchToListening(psdu, m_staMac->GetAssociationId(), m_self))
1359 m_ongoingTxopEnd.Cancel();
1360 m_staMac->GetEmlsrManager()->NotifyTxopEnd(m_linkId);
1364 UpdateTxopEndOnRxEnd(psdu->GetDuration());
1368 if (m_staMac && m_dlTxopStart)
1372 m_ongoingTxopEnd.Cancel();
1373 NS_LOG_DEBUG(
"Expected TXOP end=" << (Simulator::Now() + m_phy->GetSifs()).As(Time::S));
1374 m_ongoingTxopEnd = Simulator::Schedule(m_phy->GetSifs() + TimeStep(1),
1375 &EhtFrameExchangeManager::TxopEnd,
1379 m_staMac->GetEmlsrManager()->NotifyDlTxopStart(m_linkId);
1380 m_dlTxopStart =
false;
1392 if (m_ongoingTxopEnd.IsPending())
1398 if (
auto holder = FindTxopHolder(hdr, txVector); holder != sender)
1400 NS_LOG_DEBUG(
"Sender (" << sender <<
") differs from the TXOP holder ("
1405 if (!GetWifiRemoteStationManager()->GetEmlsrEnabled(sender))
1407 NS_LOG_DEBUG(
"Sender (" << sender <<
") is not an EMLSR client");
1411 NS_LOG_DEBUG(
"EMLSR client " << sender <<
" is starting a TXOP");
1414 auto mldAddress = GetWifiRemoteStationManager()->GetMldAddress(sender);
1417 for (uint8_t linkId = 0; linkId < m_apMac->GetNLinks(); ++linkId)
1419 if (linkId != m_linkId &&
1420 m_mac->GetWifiRemoteStationManager(linkId)->GetEmlsrEnabled(*mldAddress))
1422 m_mac->BlockUnicastTxOnLinks(WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1430 m_mac->GetWifiRemoteStationManager(linkId)->GetAffiliatedStaAddress(*mldAddress);
1433 StaticCast<EhtFrameExchangeManager>(m_mac->GetFrameExchangeManager(linkId));
1434 NS_LOG_DEBUG(
"Remove " << *linkAddr <<
" from protected STAs");
1435 ehtFem->m_protectedStas.erase(*linkAddr);
1436 ehtFem->m_sentRtsTo.erase(*linkAddr);
1437 ehtFem->m_sentFrameTo.erase(*linkAddr);
1444 m_mac->UnblockUnicastTxOnLinks(WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
1449 if (
auto it = m_transDelayTimer.find(*mldAddress);
1450 it != m_transDelayTimer.end() && it->second.IsPending())
1452 it->second.PeekEventImpl()->Invoke();
1453 it->second.Cancel();
1460EhtFrameExchangeManager::GetOngoingTxopEndEvent()
1462 return m_ongoingTxopEnd;
1470 if (m_apMac && m_apMac->GetApEmlsrManager())
1472 m_apMac->GetApEmlsrManager()->NotifyPsduRxError(m_linkId, psdu);
1482 NS_LOG_FUNCTION(
this << *mpdu << rxSignalInfo << txVector << inAmpdu);
1485 NS_ASSERT(mpdu->GetHeader().GetAddr1().IsGroup() || mpdu->GetHeader().GetAddr1() == m_self);
1487 const auto& hdr = mpdu->GetHeader();
1488 auto sender = hdr.GetAddr2();
1490 if (hdr.IsTrigger())
1498 mpdu->GetPacket()->PeekHeader(trigger);
1500 if (hdr.GetAddr1() != m_self &&
1501 (!hdr.GetAddr1().IsBroadcast() || !m_staMac->IsAssociated() ||
1508 if ((trigger.
IsMuRts() || trigger.
IsBsrp()) && !m_ongoingTxopEnd.IsPending() &&
1509 m_staMac->IsEmlsrLink(m_linkId))
1512 if (DropReceivedIcf())
1517 m_dlTxopStart =
true;
1520 else if (m_staMac && m_staMac->IsEmlsrLink(m_linkId) && !m_ongoingTxopEnd.IsPending() &&
1521 m_phy->GetPhyId() == m_staMac->GetEmlsrManager()->GetMainPhyId() &&
1522 (hdr.IsRts() || hdr.IsBlockAckReq() || (hdr.IsData() && hdr.GetAddr1() == m_self)))
1525 m_dlTxopStart =
true;
1528 if (!m_dlTxopStart && ShallDropReceivedMpdu(mpdu))
1534 HeFrameExchangeManager::ReceiveMpdu(mpdu, rxSignalInfo, txVector, inAmpdu);
1536 if (m_apMac && GetWifiRemoteStationManager()->GetEmlsrEnabled(sender))
1538 if (hdr.IsRts() && !m_sendCtsEvent.IsPending())
1541 EmlsrSwitchToListening(sender,
Time{0});
1547 CheckEmlsrClientStartingTxop(hdr, txVector);
1555 const std::vector<bool>& perMpduStatus)
1558 this << *psdu << rxSignalInfo << txVector << perMpduStatus.size()
1559 << std::all_of(perMpduStatus.begin(), perMpduStatus.end(), [](
bool v) { return v; }));
1561 const auto& hdr = psdu->GetHeader(0);
1562 if (m_staMac && m_staMac->IsEmlsrLink(m_linkId) && !m_ongoingTxopEnd.IsPending() &&
1563 m_phy->GetPhyId() == m_staMac->GetEmlsrManager()->GetMainPhyId() &&
1564 (hdr.IsData() && hdr.GetAddr1() == m_self))
1567 m_dlTxopStart =
true;
1570 if (!m_dlTxopStart && ShallDropReceivedMpdu(*psdu->begin()))
1575 HeFrameExchangeManager::EndReceiveAmpdu(psdu, rxSignalInfo, txVector, perMpduStatus);
1584 if (!m_staMac || !m_staMac->IsEmlsrLink(m_linkId))
1601 if (m_sendCtsEvent.IsPending())
1603 NS_LOG_DEBUG(
"Dropping " << *mpdu <<
" received when CTS is scheduled for TX on link "
1608 const auto& hdr = mpdu->GetHeader();
1618 if (hdr.IsMgt() || hdr.IsCts() || hdr.IsCfEnd() || (hdr.IsData() && hdr.GetAddr1().IsGroup()))
1624 if (m_mac->GetLinkForPhy(m_staMac->GetEmlsrManager()->GetMainPhyId()) != m_linkId)
1626 NS_LOG_DEBUG(
"Dropping " << *mpdu <<
" received by an aux PHY on link " << +m_linkId);
1631 if (!m_ongoingTxopEnd.IsPending() &&
1633 return m_mac->GetQosTxop(aciAcPair.first)->GetTxopStartTime(m_linkId).has_value();
1636 NS_LOG_DEBUG(
"Dropping " << *mpdu <<
" received by main PHY on link " << +m_linkId
1637 <<
" while no TXOP is ongoing");
1646EhtFrameExchangeManager::DropReceivedIcf()
1650 auto emlsrManager = m_staMac->GetEmlsrManager();
1653 if (UsingOtherEmlsrLink())
1657 auto apMldAddress = GetWifiRemoteStationManager()->GetMldAddress(m_bssid);
1658 NS_ASSERT_MSG(apMldAddress,
"MLD address not found for " << m_bssid);
1660 if (
auto it = std::find_if(
1661 m_staMac->GetLinkIds().cbegin(),
1662 m_staMac->GetLinkIds().cend(),
1664 [=,
this](uint8_t linkId) {
1666 StaticCast<EhtFrameExchangeManager>(m_mac->GetFrameExchangeManager(linkId));
1667 return linkId != m_linkId && m_staMac->IsEmlsrLink(linkId) &&
1668 ehtFem->m_ongoingTxopEnd.IsPending() && ehtFem->m_txopHolder &&
1669 m_mac->GetWifiRemoteStationManager(linkId)->GetMldAddress(
1670 *ehtFem->m_txopHolder) == apMldAddress;
1672 it != m_staMac->GetLinkIds().cend())
1678 StaticCast<EhtFrameExchangeManager>(m_mac->GetFrameExchangeManager(*it))
1679 ->m_ongoingTxopEnd.Cancel();
1683 m_staMac->UnblockTxOnLink({m_linkId}, WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK);
1690 NS_LOG_DEBUG(
"Drop ICF because another EMLSR link is being used");
1691 m_icfDropCallback({WifiIcfDrop::USING_OTHER_LINK, m_linkId, m_bssid});
1715 else if (
auto mainPhy = m_staMac->GetDevice()->GetPhy(emlsrManager->GetMainPhyId());
1718 auto reason = emlsrManager->CheckMainPhyTakesOverDlTxop(m_linkId);
1720 if (reason.has_value())
1723 "Drop ICF due to not enough time for the main PHY to switch link; reason = "
1725 m_icfDropCallback({*reason, m_linkId, m_bssid});
1733EhtFrameExchangeManager::TxopEnd(
const std::optional<Mac48Address>& txopHolder)
1737 if (m_phy && m_phy->GetInfoIfRxingPhyHeader())
1743 NS_LOG_DEBUG(
"PHY is decoding the PHY header of PPDU, postpone TXOP end");
1745 &EhtFrameExchangeManager::TxopEnd,
1751 if (m_staMac && m_staMac->IsEmlsrLink(m_linkId))
1753 m_staMac->GetEmlsrManager()->NotifyTxopEnd(m_linkId);
1755 else if (m_apMac && txopHolder && GetWifiRemoteStationManager()->GetEmlsrEnabled(*txopHolder))
1758 EmlsrSwitchToListening(*txopHolder,
Seconds(0));
1763EhtFrameExchangeManager::UpdateTxopEndOnTxStart(
Time txDuration,
Time durationId)
1767 if (!m_ongoingTxopEnd.IsPending())
1773 m_ongoingTxopEnd.Cancel();
1776 if (m_txTimer.IsRunning())
1781 delay = m_txTimer.GetDelayLeft();
1783 else if (durationId <= m_phy->GetSifs())
1787 NS_LOG_DEBUG(
"Assume TXOP will end based on Duration/ID value");
1798 delay =
Min(delay, txDuration + durationId);
1801 NS_LOG_DEBUG(
"Expected TXOP end=" << (Simulator::Now() + delay).As(Time::S));
1803 Simulator::Schedule(delay, &EhtFrameExchangeManager::TxopEnd,
this, m_txopHolder);
1807EhtFrameExchangeManager::UpdateTxopEndOnRxStartIndication(
Time psduDuration)
1818 m_ongoingTxopEnd.Cancel();
1820 NS_LOG_DEBUG(
"Expected TXOP end=" << (Simulator::Now() + psduDuration).As(Time::S));
1821 m_ongoingTxopEnd = Simulator::Schedule(psduDuration +
NanoSeconds(1),
1822 &EhtFrameExchangeManager::TxopEnd,
1828EhtFrameExchangeManager::UpdateTxopEndOnRxEnd(
Time durationId)
1832 if (!m_ongoingTxopEnd.IsPending())
1838 m_ongoingTxopEnd.Cancel();
1842 if (durationId <= m_phy->GetSifs())
1844 NS_LOG_DEBUG(
"Assume TXOP ended based on Duration/ID value");
1845 TxopEnd(m_txopHolder);
1853 delay =
Min(delay, durationId);
1854 NS_LOG_DEBUG(
"Expected TXOP end=" << (Simulator::Now() + delay).As(Time::S));
1856 Simulator::Schedule(delay, &EhtFrameExchangeManager::TxopEnd,
this, m_txopHolder);
a polymophic address class
EhtFrameExchangeManager handles the frame exchange sequences for EHT stations.
void GenerateInDeviceInterferenceForAll(const Time &txDuration, const WifiTxVector &txVector)
Generate in-device interference caused by a transmission on this link for all the other PHYs of this ...
void ForwardPsduMapDown(WifiConstPsduMap psduMap, WifiTxVector &txVector) override
Forward a map of PSDUs down to the PHY layer.
void ReceivedQosNullAfterBsrpTf(Mac48Address sender) override
Perform the actions required when receiving QoS Null frame(s) from the given sender after a BSRP Trig...
void SetIcfPaddingAndTxVector(CtrlTriggerHeader &trigger, WifiTxVector &txVector) const
Set the padding and the TXVECTOR of the given Trigger Frame, in case it is an Initial Control Frame f...
bool UsingOtherEmlsrLink() const
void NavResetTimeout() override
Reset the NAV upon expiration of the NAV reset timer.
bool GetUpdateCwOnCtsTimeout() const override
void ForwardPsduDown(Ptr< const WifiPsdu > psdu, WifiTxVector &txVector) override
Forward a PSDU down to the PHY layer.
void EmlsrSwitchToListening(Mac48Address address, const Time &delay)
This method is intended to be called when an AP MLD detects that an EMLSR client previously involved ...
void BlockAcksInTbPpduTimeout(WifiPsduMap *psduMap, std::size_t nSolicitedStations) override
Take the necessary actions after that some BlockAck frames are missing in response to a DL MU PPDU.
void SendEmlOmn(const Mac48Address &dest, const MgtEmlOmn &frame)
Send an EML Operating Mode Notification frame to the given station.
Ptr< WifiMpdu > CreateAliasIfNeeded(Ptr< WifiMpdu > mpdu) const override
Create an alias of the given MPDU for transmission by this Frame Exchange Manager.
void ProtectionCompleted() override
Transmit prepared frame immediately, if no protection was used, or in a SIFS, if protection was compl...
void TbPpduTimeout(WifiPsduMap *psduMap, std::size_t nSolicitedStations) override
Take the necessary actions after that some TB PPDUs are missing in response to Trigger Frame.
bool GetReportRtsFailed() const override
void IntraBssNavResetTimeout() override
Reset the intra-BSS NAV upon expiration of the intra-BSS NAV reset timer.
void GenerateInDeviceInterference(Ptr< WifiPhy > phy, Time duration, Watt_u txPower)
Generate an in-device interference of the given power for the given duration for the given PHY.
void SendCtsAfterMuRts(const WifiMacHeader &muRtsHdr, const CtrlTriggerHeader &trigger, double muRtsSnr) override
Send CTS after receiving an MU-RTS.
void SwitchToListeningOrUnblockLinks(const std::set< Mac48Address > &clients)
For each EMLSR client in the given set of clients that did not respond to a frame requesting a respon...
EhtFrameExchangeManager()
bool IsCrossLinkCollision(const std::set< Mac48Address > &staMissedResponseFrom) const
Check whether all the stations that did not respond (to a certain frame) are EMLSR clients trying to ...
std::optional< dBm_u > GetMostRecentRssi(const Mac48Address &address) const override
Get the RSSI of the most recent packet received from the station having the given address.
bool EmlsrClientCannotRespondToIcf() const
bool GetEmlsrSwitchToListening(Ptr< const WifiPsdu > psdu, uint16_t aid, const Mac48Address &address) const
static TypeId GetTypeId()
Get the type ID.
void DoDispose() override
Destructor implementation.
std::unordered_map< Mac48Address, EventId, WifiAddressHash > m_transDelayTimer
MLD address-indexed map of transition delay timers.
void NotifyChannelReleased(Ptr< Txop > txop) override
Notify the given Txop that channel has been released.
EventId m_ongoingTxopEnd
event indicating the possible end of the current TXOP (of which we are not the holder)
void RxStartIndication(WifiTxVector txVector, Time psduDuration) override
void UpdateTxopEndOnTxStart(Time txDuration, Time durationId)
Update the TXOP end timer when starting a frame transmission.
void SendQosNullFramesInTbPpdu(const CtrlTriggerHeader &trigger, const WifiMacHeader &hdr) override
Send QoS Null frames in response to a Basic or BSRP Trigger Frame.
void UpdateTxopEndOnRxStartIndication(Time psduDuration)
Update the TXOP end timer when receiving a PHY-RXSTART.indication.
~EhtFrameExchangeManager() override
bool UnblockEmlsrLinksIfAllowed(Mac48Address address, bool checkThisLink)
Unblock transmissions on all the links of the given EMLSR client, provided that the latter is not inv...
void CtsAfterMuRtsTimeout(Ptr< WifiMpdu > muRts, const WifiTxVector &txVector) override
Called when no CTS frame is received after an MU-RTS.
void NotifySwitchingEmlsrLink(Ptr< WifiPhy > phy, uint8_t linkId, Time delay)
Notify that the given PHY will switch channel to operate on another EMLSR link after the given delay.
bool StartTransmission(Ptr< Txop > edca, MHz_u allowedWidth) override
Request the FrameExchangeManager to start a frame exchange sequence.
void SetLinkId(uint8_t linkId) override
Set the ID of the link this Frame Exchange Manager is associated with.
An identifier for simulation events.
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
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
virtual void ResetPhy()
Remove WifiPhy associated with this FrameExchangeManager.
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager() const
Ptr< MacTxMiddle > m_txMiddle
the MAC TX Middle on this station
virtual bool GetReportRtsFailed() const
Mac48Address m_self
the MAC address of this device
WifiTxTimer m_txTimer
the timer set upon frame transmission
std::set< Mac48Address > m_protectedStas
STAs that have replied to an RTS in this TXOP.
Mac48Address GetAddress() const
Get the MAC address.
virtual void SetLinkId(uint8_t linkId)
Set the ID of the link this Frame Exchange Manager is associated with.
Ptr< WifiAckManager > GetAckManager() const
Get the Acknowledgment Manager used by this node.
Ptr< WifiProtectionManager > GetProtectionManager() const
Get the Protection Manager used by this node.
Ptr< WifiPhy > m_phy
the PHY layer on this station
Ptr< ApWifiMac > m_apMac
AP MAC layer pointer (null if not an AP)
Mac48Address m_bssid
BSSID address (Mac48Address)
virtual bool StartTransmission(Ptr< Txop > dcf, MHz_u allowedWidth)
Request the FrameExchangeManager to start a frame exchange sequence.
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 bool GetUpdateCwOnCtsTimeout() const
HeFrameExchangeManager handles the frame exchange sequences for HE stations.
virtual void SendQosNullFramesInTbPpdu(const CtrlTriggerHeader &trigger, const WifiMacHeader &hdr)
Send QoS Null frames in response to a Basic or BSRP Trigger Frame.
void DoDispose() override
Destructor implementation.
virtual void IntraBssNavResetTimeout()
Reset the intra-BSS NAV upon expiration of the intra-BSS NAV reset timer.
virtual void ReceivedQosNullAfterBsrpTf(Mac48Address sender)
Perform the actions required when receiving QoS Null frame(s) from the given sender after a BSRP Trig...
void RxStartIndication(WifiTxVector txVector, Time psduDuration) override
virtual void CtsAfterMuRtsTimeout(Ptr< WifiMpdu > muRts, const WifiTxVector &txVector)
Called when no CTS frame is received after an MU-RTS.
void NavResetTimeout() override
Reset the NAV upon expiration of the NAV reset timer.
void ProtectionCompleted() override
Transmit prepared frame immediately, if no protection was used, or in a SIFS, if protection was compl...
virtual void SendCtsAfterMuRts(const WifiMacHeader &muRtsHdr, const CtrlTriggerHeader &trigger, double muRtsSnr)
Send CTS after receiving an MU-RTS.
virtual void BlockAcksInTbPpduTimeout(WifiPsduMap *psduMap, std::size_t nSolicitedStations)
Take the necessary actions after that some BlockAck frames are missing in response to a DL MU PPDU.
virtual void ForwardPsduMapDown(WifiConstPsduMap psduMap, WifiTxVector &txVector)
Forward a map of PSDUs down to the PHY layer.
std::set< Mac48Address > GetTfRecipients(const CtrlTriggerHeader &trigger) const
Get the (link) address of the non-AP stations solicited by the given Trigger Frame.
void DoTbPpduTimeout(WifiPsduMap *psduMap, std::size_t nSolicitedStations, bool updateFailedCw)
Take the necessary actions after that some TB PPDUs are missing in response to Trigger Frame.
virtual std::optional< dBm_u > GetMostRecentRssi(const Mac48Address &address) const
Get the RSSI of the most recent packet received from the station having the given address.
Ptr< MpduAggregator > m_mpduAggregator
A-MPDU aggregator.
virtual void ForwardPsduDown(Ptr< const WifiPsdu > psdu, WifiTxVector &txVector)
Forward a PSDU down to the PHY layer.
Ptr< MsduAggregator > m_msduAggregator
A-MSDU aggregator.
Implement the header for Action frames of type EML Operating Mode Notification.
Smart pointer class similar to boost::intrusive_ptr.
virtual Ptr< WifiMpdu > CreateAliasIfNeeded(Ptr< WifiMpdu > mpdu) const
Create an alias of the given MPDU for transmission by this Frame Exchange Manager.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
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.
void StartAccessAfterEvent(uint8_t linkId, bool hadFramesToTransmit, bool checkMediumBusy)
Request channel access on the given link after the occurrence of an event that possibly requires to g...
static constexpr bool DIDNT_HAVE_FRAMES_TO_TRANSMIT
no packet available for transmission was in the queue
static constexpr bool CHECK_MEDIUM_BUSY
generation of backoff (also) depends on the busy/idle state of the medium
static constexpr bool DONT_CHECK_MEDIUM_BUSY
generation of backoff is independent of the busy/idle state of the medium
a unique identifier for an interface.
TypeId SetParent(TypeId tid)
Set the parent TypeId.
uint64_t GetDataRate(MHz_u channelWidth, Time guardInterval, uint8_t nss) const
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.
const std::set< Mac48Address > & GetStasExpectedToRespond() const
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
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.
WifiPreamble GetPreambleType() const
void SetSigBMode(const WifiMode &mode)
Set the MCS used for SIG-B.
uint8_t GetTxPowerLevel() const
Declaration of ns3::EhtPhy class.
#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_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
#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_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_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 MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Time Seconds(double value)
Construct a Time in the indicated unit.
@ WIFI_MOD_CLASS_EHT
EHT (Clause 36)
@ WAITING_EMLSR_TRANSITION_DELAY
Every class exported by the ns3 library is enclosed in the ns3 namespace.
U * PeekPointer(const Ptr< U > &p)
static constexpr uint8_t WAIT_FOR_RXSTART_DELAY_USEC
Additional time (exceeding 20 us) to wait for a PHY-RXSTART.indication when the PHY is decoding a PHY...
bool IsTrigger(const WifiPsduMap &psduMap)
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
std::unordered_map< uint16_t, Ptr< WifiPsdu > > WifiPsduMap
Map of PSDUs indexed by STA-ID.
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...
Watt_u DbmToW(dBm_u val)
Convert from dBm to Watts.
std::tuple< WifiContainerQueueType, WifiRcvAddr, Mac48Address, std::optional< uint8_t > > WifiContainerQueueId
Tuple (queue type, receiver address type, Address, TID) identifying a container queue.
Ptr< T1 > StaticCast(const Ptr< T2 > &p)
Cast a Ptr.
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
const Time EMLSR_RX_PHY_START_DELAY
aRxPHYStartDelay value to use when waiting for a new frame in the context of EMLSR operations (Sec.
static Time DecodeEmlsrTransitionDelay(uint8_t value)
RxSignalInfo structure containing info on the received signal.