26#include "ns3/ap-wifi-mac.h"
28#include "ns3/mgt-action-headers.h"
29#include "ns3/sta-wifi-mac.h"
30#include "ns3/wifi-mac-queue.h"
31#include "ns3/wifi-net-device.h"
33#undef NS_LOG_APPEND_CONTEXT
34#define NS_LOG_APPEND_CONTEXT WIFI_FEM_NS_LOG_APPEND_CONTEXT
66 static TypeId tid =
TypeId(
"ns3::EhtFrameExchangeManager")
68 .AddConstructor<EhtFrameExchangeManager>()
69 .SetGroupName(
"Wifi");
105 protectionManager->SetLinkId(linkId);
109 ackManager->SetLinkId(linkId);
123 mpdu->GetHeader().GetAddr1().IsGroup() ||
130 auto& hdr = mpdu->GetHeader();
134 hdr.SetAddr1(*address);
142 if (hdr.IsQosAmsdu())
144 if (hdr.IsToDs() && !hdr.IsFromDs())
147 hdr.SetAddr3(hdr.GetAddr1());
149 else if (!hdr.IsToDs() && hdr.IsFromDs())
152 hdr.SetAddr3(hdr.GetAddr2());
190 std::set<Mac48Address> emlsrClients;
195 ehtFem->m_ongoingTxopEnd.IsPending() && ehtFem->m_txopHolder &&
197 ehtFem->m_txopHolder.value()))
199 emlsrClients.insert(ehtFem->m_txopHolder.value());
207 emlsrClients.insert(address);
211 for (
const auto& address : emlsrClients)
215 NS_ASSERT_MSG(mldAddress,
"MLD address not found for " << address);
228 "No mask for client " << *mldAddress <<
" on link " << +
m_linkId);
233 "Transmissions to " << *mldAddress <<
" on link " << +
m_linkId
234 <<
" are not blocked");
245 std::optional<Time> timeToCtsEnd;
252 NS_LOG_DEBUG(
"StartTransmission called while another EMLSR link is being used");
259 if (
auto elapsed = emlsrManager->GetElapsedMediumSyncDelayTimer(
m_linkId);
260 elapsed && emlsrManager->MediumSyncDelayNTxopsExceeded(
m_linkId))
262 NS_LOG_DEBUG(
"No new TXOP attempts allowed while MediumSyncDelay is running");
266 emlsrManager->GetMediumSyncDuration() - *elapsed,
288 if (!emlsrManager->GetAuxPhyTxCapable())
290 NS_LOG_DEBUG(
"Aux PHY is not capable of transmitting a PPDU");
295 if (mainPhy->IsStateRx())
298 "Main PHY is receiving a PPDU (may be, e.g., an ICF or a Beacon); do not "
299 "transmit to avoid dropping that PPDU due to the main PHY switching to this "
300 "link to take over the TXOP");
310 const auto rtsTxVector =
312 const auto rtsTxTime =
314 const auto ctsTxVector =
316 const auto ctsTxTime =
321 timeToCtsEnd = rtsTxTime +
m_phy->
GetSifs() + ctsTxTime +
324 auto switchingTime = mainPhy->GetChannelSwitchDelay();
326 if (mainPhy->IsStateSwitching())
330 switchingTime += mainPhy->GetDelayUntilIdle();
333 if (switchingTime > timeToCtsEnd)
337 NS_LOG_DEBUG(
"Main PHY will still be switching channel when RTS/CTS ends, thus it "
338 "will not be able to take over this TXOP");
372 auto sigBMode = phy->GetSigBMode(txVector);
422 if (
auto psduMapIt = psduMap.find(aid);
424 (psduMapIt == psduMap.cend() ||
469 NS_ASSERT_MSG(mldAddress,
"MLD address not found for " << address);
476 ehtFem->m_ongoingTxopEnd.IsPending() && ehtFem->m_txopHolder &&
490 std::set<uint8_t> linkIds;
495 linkIds.insert(linkId);
499 auto blockLinks = [=,
this]() {
514 auto unblockLinks = [=,
this]() {
521 emlCapabilities->get().emlsrTransitionDelay);
523 endDelay.IsZero() ? unblockLinks()
565 const auto sequence =
m_txMiddle->GetNextSequenceNumberFor(&hdr);
573 auto packet = Create<Packet>();
574 packet->AddHeader(frame);
575 packet->AddHeader(actionHdr);
601 std::optional<Mac48Address> linkAddress;
619 uint8_t maxPaddingDelay = 0;
631 maxPaddingDelay = std::max(maxPaddingDelay, emlCapabilities->get().emlsrPaddingDelay);
649 if (maxPaddingDelay > 0)
657 auto rate = protection->muRtsTxVector.GetMode().GetDataRate(protection->muRtsTxVector);
658 std::size_t nDbps = rate / 1e6 * 4;
659 protection->muRts.SetPaddingSize((1 << (maxPaddingDelay + 2)) * nDbps / 8);
683 NS_LOG_DEBUG(
"Main PHY is switching or operating on another link, abort sending CTS");
714 std::set<uint8_t> linkIds;
720 linkIds.insert(linkId);
755 NS_ASSERT_MSG(mask,
"No mask for client " << *mldAddress <<
" on link " << +linkId);
760 "Transmissions to " << *mldAddress <<
" on link " << +linkId
761 <<
" are not blocked");
788 if (psdu->GetAddr1() == address)
797 if (mpdu->GetHeader().IsTrigger())
800 mpdu->GetPacket()->PeekHeader(trigger);
810 if (psdu->GetHeader(0).IsCts())
824 if (psdu->GetHeader(0).IsBlockAck())
827 psdu->GetPayload(0)->PeekHeader(blockAck);
849 NS_LOG_DEBUG(
"Reset the counter of TXOP attempts allowed while "
850 "MediumSyncDelay is running");
865 NS_LOG_DEBUG(
"Decrement the remaining number of TXOP attempts allowed while "
866 "MediumSyncDelay is running");
893 auto edca = DynamicCast<QosTxop>(txop);
895 auto txopStart = edca->GetTxopStartTime(
m_linkId);
1005 if (
auto holder =
FindTxopHolder(hdr, txVector); holder != sender)
1007 NS_LOG_DEBUG(
"Sender (" << sender <<
") differs from the TXOP holder ("
1014 NS_LOG_DEBUG(
"Sender (" << sender <<
") is not an EMLSR client");
1018 NS_LOG_DEBUG(
"EMLSR client " << sender <<
" is starting a TXOP");
1046 it->second.PeekEventImpl()->Invoke();
1047 it->second.Cancel();
1060 NS_ASSERT(mpdu->GetHeader().GetAddr1().IsGroup() || mpdu->GetHeader().GetAddr1() ==
m_self);
1062 const auto& hdr = mpdu->GetHeader();
1071 bool icfReceived =
false;
1073 if (hdr.IsTrigger())
1081 mpdu->GetPacket()->PeekHeader(trigger);
1083 if (hdr.GetAddr1() !=
m_self &&
1100 NS_LOG_DEBUG(
"Drop ICF because another EMLSR link is being used");
1131 const auto delay = mainPhy->GetChannelSwitchDelay();
1133 if (mainPhy->GetState()->GetLastTime({WifiPhyState::TX,
1135 WifiPhyState::SWITCHING,
1136 WifiPhyState::SLEEP}) >
1139 NS_LOG_DEBUG(
"Drop ICF due to not enough time for the main PHY to switch link");
1144 emlsrManager->NotifyIcfReceived(
m_linkId);
1168 !icfReceived && !mpdu->GetHeader().IsCts() && !mpdu->GetHeader().IsMgt())
1188 NS_LOG_DEBUG(
"PHY is decoding the PHY header of PPDU, postpone TXOP end");
1228 else if (durationId <= m_phy->GetSifs())
1232 NS_LOG_DEBUG(
"Assume TXOP will end based on Duration/ID value");
1286 if (durationId <= m_phy->GetSifs())
1288 NS_LOG_DEBUG(
"Assume TXOP ended based on Duration/ID value");
a polymophic address class
EhtFrameExchangeManager handles the frame exchange sequences for EHT stations.
void PostProcessFrame(Ptr< const WifiPsdu > psdu, const WifiTxVector &txVector) override
Perform actions that are possibly needed after receiving any frame, independently of whether the fram...
void ForwardPsduMapDown(WifiConstPsduMap psduMap, WifiTxVector &txVector) override
Forward a map of PSDUs down to the PHY layer.
bool UsingOtherEmlsrLink() const
void PreProcessFrame(Ptr< const WifiPsdu > psdu, const WifiTxVector &txVector) override
Perform actions that are possibly needed when receiving any frame, independently of whether the frame...
void NavResetTimeout() override
Reset the NAV upon expiration of the NAV reset timer.
void ForwardPsduDown(Ptr< const WifiPsdu > psdu, WifiTxVector &txVector) override
Forward a PSDU down to the PHY layer.
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 TransmissionFailed() override
Take necessary actions upon a transmission failure.
void IntraBssNavResetTimeout() override
Reset the intra-BSS NAV upon expiration of the intra-BSS NAV reset timer.
void SendMuRts(const WifiTxParameters &txParams) override
Send an MU-RTS to begin an MU-RTS/CTS frame exchange protecting an MU PPDU.
void SendCtsAfterMuRts(const WifiMacHeader &muRtsHdr, const CtrlTriggerHeader &trigger, double muRtsSnr) override
Send CTS after receiving an MU-RTS.
EhtFrameExchangeManager()
void UpdateTxopEndOnRxEnd(Time durationId)
Update the TXOP end timer when a frame reception ends.
bool CheckEmlsrClientStartingTxop(const WifiMacHeader &hdr, const WifiTxVector &txVector)
Check if the frame received (or being received) is sent by an EMLSR client to start an UL TXOP.
void TransmissionSucceeded() override
Take necessary actions upon a transmission success.
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.
bool StartTransmission(Ptr< Txop > edca, uint16_t allowedWidth) override
Request the FrameExchangeManager to start a frame exchange sequence.
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 ReceiveMpdu(Ptr< const WifiMpdu > mpdu, RxSignalInfo rxSignalInfo, const WifiTxVector &txVector, bool inAmpdu) override
This method handles the reception of an MPDU (possibly included in an A-MPDU)
void UpdateTxopEndOnTxStart(Time txDuration, Time durationId)
Update the TXOP end timer when starting a frame transmission.
void SendCtsAfterRts(const WifiMacHeader &rtsHdr, WifiMode rtsTxMode, double rtsSnr) override
Send CTS after receiving RTS.
void UpdateTxopEndOnRxStartIndication(Time psduDuration)
Update the TXOP end timer when receiving a PHY-RXSTART.indication.
~EhtFrameExchangeManager() override
void EmlsrSwitchToListening(const Mac48Address &address, const Time &delay)
This method is intended to be called when an AP MLD detects that an EMLSR client previously involved ...
void TxopEnd(const std::optional< Mac48Address > &txopHolder)
Take actions when a TXOP (of which we are not the holder) ends.
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.
std::optional< double > GetMostRecentRssi(const Mac48Address &address) const override
Get the RSSI (in dBm) of the most recent packet received from the station having the given address.
void SetLinkId(uint8_t linkId) override
Set the ID of the link this Frame Exchange Manager is associated with.
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
virtual void ResetPhy()
Remove WifiPhy associated with this FrameExchangeManager.
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager() const
Ptr< MacTxMiddle > m_txMiddle
the MAC TX Middle on this station
Mac48Address m_self
the MAC address of this device
virtual void TransmissionFailed()
Take necessary actions upon a transmission failure.
WifiTxTimer m_txTimer
the timer set upon frame transmission
virtual void SendCtsAfterRts(const WifiMacHeader &rtsHdr, WifiMode rtsTxMode, double rtsSnr)
Send CTS after receiving RTS.
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.
virtual void NotifyChannelReleased(Ptr< Txop > txop)
Notify the given Txop that channel has been released.
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
virtual void PreProcessFrame(Ptr< const WifiPsdu > psdu, const WifiTxVector &txVector)
Perform actions that are possibly needed when receiving any frame, independently of whether the frame...
Mac48Address m_bssid
BSSID address (Mac48Address)
virtual bool StartTransmission(Ptr< Txop > dcf, uint16_t allowedWidth)
Request the FrameExchangeManager to start a frame exchange sequence.
HeFrameExchangeManager handles the frame exchange sequences for HE stations.
Ptr< ApWifiMac > m_apMac
MAC pointer (null if not an AP)
void DoDispose() override
Destructor implementation.
virtual void IntraBssNavResetTimeout()
Reset the intra-BSS NAV upon expiration of the intra-BSS NAV reset timer.
virtual void SendMuRts(const WifiTxParameters &txParams)
Send an MU-RTS to begin an MU-RTS/CTS frame exchange protecting an MU PPDU.
void RxStartIndication(WifiTxVector txVector, Time psduDuration) override
std::optional< Mac48Address > FindTxopHolder(const WifiMacHeader &hdr, const WifiTxVector &txVector) override
Determine the holder of the TXOP, if possible, based on the received frame.
virtual std::optional< double > GetMostRecentRssi(const Mac48Address &address) const
Get the RSSI (in dBm) of the most recent packet received from the station having the given address.
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.
virtual void SendCtsAfterMuRts(const WifiMacHeader &muRtsHdr, const CtrlTriggerHeader &trigger, double muRtsSnr)
Send CTS after receiving an MU-RTS.
Ptr< StaWifiMac > m_staMac
MAC pointer (null if not a STA)
void ReceiveMpdu(Ptr< const WifiMpdu > mpdu, RxSignalInfo rxSignalInfo, const WifiTxVector &txVector, bool inAmpdu) override
This method handles the reception of an MPDU (possibly included in an A-MPDU)
virtual void ForwardPsduMapDown(WifiConstPsduMap psduMap, WifiTxVector &txVector)
Forward a map of PSDUs down to the PHY layer.
void PostProcessFrame(Ptr< const WifiPsdu > psdu, const WifiTxVector &txVector) override
Perform actions that are possibly needed after receiving any frame, independently of whether the fram...
void TransmissionSucceeded() override
Take necessary actions upon a transmission success.
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.
std::optional< Mac48Address > m_txopHolder
MAC address of the TXOP holder.
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.
static Time Now()
Return the current simulation virtual time.
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
uint16_t GetAssociationId() const
Return the association ID.
void NotifySwitchingEmlsrLink(Ptr< WifiPhy > phy, uint8_t linkId, Time delay)
Notify that the given PHY switched channel to operate on another EMLSR link.
Ptr< EmlsrManager > GetEmlsrManager() const
bool IsEmlsrLink(uint8_t linkId) const
bool IsAssociated() const
Return whether we are associated with an AP.
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
virtual void Queue(Ptr< Packet > packet, const WifiMacHeader &hdr)
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.
Ptr< FrameExchangeManager > GetFrameExchangeManager(uint8_t linkId=SINGLE_LINK_OP_ID) const
Get the Frame Exchange Manager associated with the given link.
std::optional< Mac48Address > GetMldAddress(const Mac48Address &remoteAddr) const
Ptr< WifiMacQueueScheduler > GetMacQueueScheduler() const
Get the wifi MAC queue scheduler.
uint8_t GetNLinks() const
Get the number of links (can be greater than 1 for 11be devices only).
void UnblockUnicastTxOnLinks(WifiQueueBlockedReason reason, const Mac48Address &address, const std::set< uint8_t > &linkIds)
Unblock the transmission on the given links of all unicast frames addressed to the station with the g...
void BlockUnicastTxOnLinks(WifiQueueBlockedReason reason, const Mac48Address &address, const std::set< uint8_t > &linkIds)
Block the transmission on the given links of all unicast frames addressed to the station with the giv...
Ptr< WifiNetDevice > GetDevice() const
Return the device this PHY is associated with.
std::optional< uint8_t > GetLinkForPhy(Ptr< const WifiPhy > phy) const
Get the ID of the link (if any) on which the given PHY is operating.
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager(uint8_t linkId=0) const
Ptr< QosTxop > GetQosTxop(AcIndex ac) const
Accessor for a specified EDCA object.
represent a single transmission mode
Ptr< WifiPhy > GetPhy() const
Time GetSlot() const
Return the slot duration for this PHY.
Time GetSifs() const
Return the Short Interframe Space (SIFS) for this PHY.
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
WifiPhyBand GetPhyBand() const
Get the configured Wi-Fi band.
bool IsReceivingPhyHeader() const
Ptr< PhyEntity > GetPhyEntity(WifiModulationClass modulation) const
Get the supported PHY entity corresponding to the modulation class.
This class stores the TX parameters (TX vector, protection mechanism, acknowledgment mechanism,...
std::unique_ptr< WifiProtection > m_protection
protection method
bool IsRunning() const
Return true if the timer is running.
const std::set< Mac48Address > & GetStasExpectedToRespond() const
Time GetDelayLeft() const
Get the remaining time until the timer will expire.
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
WifiPreamble GetPreambleType() const
void SetSigBMode(const WifiMode &mode)
Set the MCS used for SIG-B.
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_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
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)
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
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...
static constexpr uint8_t RX_PHY_START_DELAY_USEC
aRxPHYStartDelay value to use when waiting for a new frame in the context of EMLSR operations (Sec.
uint32_t GetRtsSize()
Return the total RTS size (including FCS trailer).
std::tuple< WifiContainerQueueType, WifiReceiverAddressType, Mac48Address, std::optional< uint8_t > > WifiContainerQueueId
Tuple (queue type, receiver address type, Address, TID) identifying a container queue.
static constexpr uint8_t MAX_PROPAGATION_DELAY_USEC
maximum propagation delay
uint32_t GetCtsSize()
Return the total CTS size (including FCS trailer).
static Time DecodeEmlsrTransitionDelay(uint8_t value)
RxSignalInfo structure containing info on the received signal.
WifiMuRtsCtsProtection specifies that MU-RTS/CTS protection method is used.