A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
wifi-default-protection-manager.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2020 Universita' degli Studi di Napoli Federico II
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Stefano Avallone <stavallo@unina.it>
7 */
8
10
11#include "ap-wifi-mac.h"
12#include "sta-wifi-mac.h"
13#include "wifi-mpdu.h"
14#include "wifi-tx-parameters.h"
15
16#include "ns3/boolean.h"
17#include "ns3/eht-frame-exchange-manager.h"
18#include "ns3/emlsr-manager.h"
19#include "ns3/erp-ofdm-phy.h"
20#include "ns3/log.h"
21
22#include <type_traits>
23
24namespace ns3
25{
26
27NS_LOG_COMPONENT_DEFINE("WifiDefaultProtectionManager");
28
30
33{
34 static TypeId tid =
35 TypeId("ns3::WifiDefaultProtectionManager")
37 .SetGroupName("Wifi")
38 .AddConstructor<WifiDefaultProtectionManager>()
39 .AddAttribute("EnableMuRts",
40 "If enabled, always protect a DL/UL MU frame exchange with MU-RTS/CTS.",
41 BooleanValue(false),
44 .AddAttribute("SingleRtsPerTxop",
45 "If enabled, a protection mechanism (RTS or MU-RTS) is normally used no "
46 "more than once in a TXOP, regardless of the destination of the data "
47 "frame (unless required for specific purposes, such as transmitting an "
48 "Initial Control Frame to an EMLSR client).",
49 BooleanValue(false),
52 .AddAttribute("SkipMuRtsBeforeBsrp",
53 "If enabled, MU-RTS is not used to protect the transmission of a BSRP "
54 "Trigger Frame.",
55 BooleanValue(true),
58 return tid;
59}
60
65
70
71std::unique_ptr<WifiProtection>
73{
74 NS_LOG_FUNCTION(this << *mpdu << &txParams);
75
76 const auto& hdr = mpdu->GetHeader();
77
78 if (hdr.IsPsPoll())
79 {
80 NS_ASSERT(!txParams.m_protection);
81 return std::make_unique<WifiNoProtection>();
82 }
83
84 // Call a separate method that handles MU-RTS/CTS protection in case of DL MU PPDU containing
85 // more than one PSDU or in case the MPDU being added is addressed to an EMLSR client or in
86 // case the protection method is already MU-RTS/CTS.
87 const auto& psduInfoMap = txParams.GetPsduInfoMap();
88 auto dlMuPpdu = txParams.m_txVector.IsDlMu() && psduInfoMap.size() > 1;
89 auto isEmlsrDestination = GetWifiRemoteStationManager()->GetEmlsrEnabled(hdr.GetAddr1());
90
91 if (dlMuPpdu || isEmlsrDestination ||
92 (txParams.m_protection && txParams.m_protection->method == WifiProtection::MU_RTS_CTS))
93 {
94 return TryAddMpduToMuPpdu(mpdu, txParams);
95 }
96
97 // No protection for TB PPDUs (the soliciting Trigger Frame can be protected by an MU-RTS)
98 if (txParams.m_txVector.IsUlMu())
99 {
100 if (txParams.m_protection)
101 {
102 NS_ASSERT(txParams.m_protection->method == WifiProtection::NONE);
103 return nullptr;
104 }
105 return std::make_unique<WifiNoProtection>();
106 }
107
108 // if this is a Trigger Frame, call a separate method
109 if (hdr.IsTrigger())
110 {
111 return TryUlMuTransmission(mpdu, txParams);
112 }
113
114 // if the current protection method (if any) is already RTS/CTS or CTS-to-Self,
115 // it will not change by adding an MPDU
116 if (txParams.m_protection && (txParams.m_protection->method == WifiProtection::RTS_CTS ||
117 txParams.m_protection->method == WifiProtection::CTS_TO_SELF))
118 {
119 return nullptr;
120 }
121
122 // if a protection method is set, it must be NONE
123 NS_ASSERT(!txParams.m_protection || txParams.m_protection->method == WifiProtection::NONE);
124
125 std::unique_ptr<WifiProtection> protection;
126 protection = GetPsduProtection(hdr, txParams);
127
128 // return the newly computed method if none was set or it is not NONE
129 if (!txParams.m_protection || protection->method != WifiProtection::NONE)
130 {
131 return protection;
132 }
133 // the protection method has not changed
134 return nullptr;
135}
136
137std::unique_ptr<WifiProtection>
139 const WifiTxParameters& txParams)
140{
141 NS_LOG_FUNCTION(this << *msdu << &txParams);
142
143 // if the current protection method is already RTS/CTS, CTS-to-Self or MU-RTS/CTS,
144 // it will not change by aggregating an MSDU
145 NS_ASSERT(txParams.m_protection);
146 if (txParams.m_protection->method == WifiProtection::RTS_CTS ||
147 txParams.m_protection->method == WifiProtection::CTS_TO_SELF ||
148 txParams.m_protection->method == WifiProtection::MU_RTS_CTS)
149 {
150 return nullptr;
151 }
152
153 NS_ASSERT(txParams.m_protection->method == WifiProtection::NONE);
154
155 // No protection for TB PPDUs and DL MU PPDUs containing more than one PSDU
156 if (txParams.m_txVector.IsUlMu() ||
157 (txParams.m_txVector.IsDlMu() && txParams.GetPsduInfoMap().size() > 1))
158 {
159 return nullptr;
160 }
161
162 std::unique_ptr<WifiProtection> protection;
163 protection = GetPsduProtection(msdu->GetHeader(), txParams);
164
165 // the protection method may still be none
166 if (protection->method == WifiProtection::NONE)
167 {
168 return nullptr;
169 }
170
171 // the protection method has changed
172 return protection;
173}
174
175std::unique_ptr<WifiProtection>
177 const WifiTxParameters& txParams) const
178{
179 NS_LOG_FUNCTION(this << hdr << &txParams);
180
181 // a non-initial fragment does not need to be protected, unless it is being retransmitted
182 if (hdr.GetFragmentNumber() > 0 && !hdr.IsRetry())
183 {
184 return std::make_unique<WifiNoProtection>();
185 }
186
187 // no need to use protection if destination already received an RTS in this TXOP or
188 // SingleRtsPerTxop is true and a protection mechanism has been already used in this TXOP
189 if (const auto& protectedStas = m_mac->GetFrameExchangeManager(m_linkId)->GetProtectedStas();
190 protectedStas.contains(hdr.GetAddr1()) || (m_singleRtsPerTxop && !protectedStas.empty()))
191 {
192 return std::make_unique<WifiNoProtection>();
193 }
194
195 // when an EMLSR client starts an UL TXOP on a link while the MediumSyncDelay timer is running
196 // or on a link on which the main PHY is not operating, it needs to send an RTS frame
197 bool emlsrNeedRts = false;
198
199 if (auto staMac = DynamicCast<StaWifiMac>(m_mac))
200 {
201 auto emlsrManager = staMac->GetEmlsrManager();
202
203 emlsrNeedRts = emlsrManager && staMac->IsEmlsrLink(m_linkId) &&
204 (emlsrManager->GetElapsedMediumSyncDelayTimer(m_linkId) ||
205 m_mac->GetLinkForPhy(emlsrManager->GetMainPhyId()) != m_linkId);
206 }
207
208 // check if RTS/CTS is needed
209 if (emlsrNeedRts || GetWifiRemoteStationManager()->NeedRts(hdr, txParams))
210 {
211 auto protection = std::make_unique<WifiRtsCtsProtection>();
212 protection->rtsTxVector =
213 GetWifiRemoteStationManager()->GetRtsTxVector(hdr.GetAddr1(),
214 txParams.m_txVector.GetChannelWidth());
215 protection->ctsTxVector =
216 GetWifiRemoteStationManager()->GetCtsTxVector(hdr.GetAddr1(),
217 protection->rtsTxVector.GetMode());
218 return protection;
219 }
220
221 // check if CTS-to-Self is needed
222 if (GetWifiRemoteStationManager()->NeedCtsToSelf(txParams.m_txVector, hdr))
223 {
224 auto protection = std::make_unique<WifiCtsToSelfProtection>();
225 protection->ctsTxVector = GetWifiRemoteStationManager()->GetCtsToSelfTxVector();
226 return protection;
227 }
228
229 return std::make_unique<WifiNoProtection>();
230}
231
232std::unique_ptr<WifiProtection>
234 const WifiTxParameters& txParams)
235{
236 NS_LOG_FUNCTION(this << *mpdu << &txParams);
237
238 auto receiver = mpdu->GetHeader().GetAddr1();
239 const auto& psduInfoMap = txParams.GetPsduInfoMap();
240 auto dlMuPpdu = txParams.m_txVector.IsDlMu() && psduInfoMap.size() > 1;
241 auto isEmlsrDestination = GetWifiRemoteStationManager()->GetEmlsrEnabled(receiver);
242 NS_ASSERT(
243 dlMuPpdu || isEmlsrDestination ||
244 (txParams.m_protection && txParams.m_protection->method == WifiProtection::MU_RTS_CTS));
245
246 const auto& protectedStas = m_mac->GetFrameExchangeManager(m_linkId)->GetProtectedStas();
247 const auto isProtected = protectedStas.contains(receiver);
248 bool needMuRts =
249 (txParams.m_protection && txParams.m_protection->method == WifiProtection::MU_RTS_CTS) ||
250 (dlMuPpdu && m_sendMuRts && !isProtected &&
251 (!m_singleRtsPerTxop || protectedStas.empty())) ||
252 (isEmlsrDestination && !isProtected);
253
254 if (!needMuRts)
255 {
256 // No protection needed
257 if (txParams.m_protection && txParams.m_protection->method == WifiProtection::NONE)
258 {
259 return nullptr;
260 }
261 return std::make_unique<WifiNoProtection>();
262 }
263
264 WifiMuRtsCtsProtection* protection = nullptr;
265 if (txParams.m_protection && txParams.m_protection->method == WifiProtection::MU_RTS_CTS)
266 {
267 protection = static_cast<WifiMuRtsCtsProtection*>(txParams.m_protection.get());
268 }
269
270 if (txParams.LastAddedIsFirstMpdu(receiver))
271 {
272 // we get here if this is the first MPDU for this receiver.
273 NS_ABORT_MSG_IF(m_mac->GetTypeOfStation() != AP, "HE APs only can send DL MU PPDUs");
274 auto modClass = txParams.m_txVector.GetModulationClass();
275 auto txWidth = modClass == WIFI_MOD_CLASS_DSSS || modClass == WIFI_MOD_CLASS_HR_DSSS
276 ? MHz_u{20}
277 : txParams.m_txVector.GetChannelWidth();
278
279 if (protection != nullptr)
280 {
281 // txParams.m_protection points to an existing WifiMuRtsCtsProtection object.
282 // We have to return a copy of this object including the needed changes
283 protection = new WifiMuRtsCtsProtection(*protection);
284
285 // Add a User Info field for the new receiver
286 // The UL HE-MCS, UL FEC Coding Type, UL DCM, SS Allocation and UL Target RSSI fields
287 // in the User Info field are reserved (Sec. 9.3.1.22.5 of 802.11ax)
288 AddUserInfoToMuRts(protection->muRts, txWidth, receiver);
289 }
290 else
291 {
292 // we have to create a new WifiMuRtsCtsProtection object
293 protection = new WifiMuRtsCtsProtection;
294
295 // initialize the MU-RTS Trigger Frame
296 // The UL Length, GI And HE-LTF Type, MU-MIMO HE-LTF Mode, Number Of HE-LTF Symbols,
297 // UL STBC, LDPC Extra Symbol Segment, AP TX Power, Pre-FEC Padding Factor,
298 // PE Disambiguity, UL Spatial Reuse, Doppler and UL HE-SIG-A2 Reserved subfields in
299 // the Common Info field are reserved. (Sec. 9.3.1.22.5 of 802.11ax)
301 /* 35.2.2.1 MU-RTS Trigger frame transmission (IEEE P802.11be/D7.0):
302 * If a non-AP EHT STA is addressed in an MU-RTS Trigger frame from an EHT AP and any of
303 * the following conditions is met, the User Info field addressed to an EHT STA in the
304 * MU-RTS Trigger frame shall be an EHT variant User Info field:
305 * - The bandwidth of the EHT MU PPDU or non-HT duplicate PPDU carrying the MU-RTS
306 * Trigger frame is 320 MHz.
307 * - The EHT MU PPDU or non-HT duplicate PPDU carrying the MU-RTS Trigger frame is
308 * punctured. Otherwise, the EHT AP may decide whether the User Info field in the MU-RTS
309 * Trigger frame is an HE variant User Info field or an EHT variant User Info field.
310 */
311 const auto& inactiveSubchannels = txParams.m_txVector.GetInactiveSubchannels();
312 const auto isPunctured =
313 std::find(inactiveSubchannels.cbegin(), inactiveSubchannels.cend(), true) !=
314 inactiveSubchannels.cend();
315 const auto muRtsVariant = ((txWidth == MHz_u{320}) || isPunctured)
318 protection->muRts.SetVariant(muRtsVariant);
319 protection->muRts.SetUlBandwidth(txWidth);
320
321 // Add a User Info field for each of the receivers already in the TX params
322 for (const auto& [address, info] : txParams.GetPsduInfoMap())
323 {
324 AddUserInfoToMuRts(protection->muRts, txWidth, address);
325 }
326
327 // compute the TXVECTOR to use to send the MU-RTS Trigger Frame
328 protection->muRtsTxVector =
329 GetWifiRemoteStationManager()->GetRtsTxVector(receiver, txWidth);
330 // The transmitter of an MU-RTS Trigger frame shall not request a non-AP STA to send
331 // a CTS frame response in a 20 MHz channel that is not occupied by the PPDU that
332 // contains the MU-RTS Trigger frame. (Sec. 26.2.6.2 of 802.11ax)
333 protection->muRtsTxVector.SetChannelWidth(txWidth);
334 // OFDM is needed to transmit the PPDU over a bandwidth that is a multiple of 20 MHz
335 const auto modulation = protection->muRtsTxVector.GetModulationClass();
336 if (modulation == WIFI_MOD_CLASS_DSSS || modulation == WIFI_MOD_CLASS_HR_DSSS)
337 {
339 }
340 }
341
342 if (isEmlsrDestination && !isProtected)
343 {
344 // This MU-RTS is an ICF for some EMLSR client
345 auto ehtFem =
346 StaticCast<EhtFrameExchangeManager>(m_mac->GetFrameExchangeManager(m_linkId));
347 ehtFem->SetIcfPaddingAndTxVector(protection->muRts, protection->muRtsTxVector);
348 }
349
350 return std::unique_ptr<WifiMuRtsCtsProtection>(protection);
351 }
352
353 // an MPDU addressed to the same receiver has been already added
354 NS_ASSERT(protection != nullptr);
355
356 // no change is needed
357 return nullptr;
358}
359
360std::unique_ptr<WifiProtection>
362 const WifiTxParameters& txParams)
363{
364 NS_LOG_FUNCTION(this << *mpdu << &txParams);
365 NS_ASSERT(mpdu->GetHeader().IsTrigger());
366
367 CtrlTriggerHeader trigger;
368 mpdu->GetPacket()->PeekHeader(trigger);
369 NS_ASSERT(trigger.GetNUserInfoFields() > 0);
370 auto txWidth = trigger.GetUlBandwidth();
371
372 auto protection = std::make_unique<WifiMuRtsCtsProtection>();
373 // initialize the MU-RTS Trigger Frame
374 // The UL Length, GI And HE-LTF Type, MU-MIMO HE-LTF Mode, Number Of HE-LTF Symbols,
375 // UL STBC, LDPC Extra Symbol Segment, AP TX Power, Pre-FEC Padding Factor,
376 // PE Disambiguity, UL Spatial Reuse, Doppler and UL HE-SIG-A2 Reserved subfields in
377 // the Common Info field are reserved. (Sec. 9.3.1.22.5 of 802.11ax)
378 protection->muRts.SetType(TriggerFrameType::MU_RTS_TRIGGER);
379 protection->muRts.SetVariant(trigger.GetVariant());
380 protection->muRts.SetUlBandwidth(txWidth);
381
382 NS_ABORT_MSG_IF(m_mac->GetTypeOfStation() != AP, "HE APs only can send DL MU PPDUs");
383 const auto& staList = StaticCast<ApWifiMac>(m_mac)->GetStaList(m_linkId);
384
385 const auto& protectedStas = m_mac->GetFrameExchangeManager(m_linkId)->GetProtectedStas();
386 bool allProtected = true;
387 bool isUnprotectedEmlsrDst = false;
388
389 for (const auto& userInfo : trigger)
390 {
391 // Add a User Info field to the MU-RTS for this solicited station
392 // The UL HE-MCS, UL FEC Coding Type, UL DCM, SS Allocation and UL Target RSSI fields
393 // in the User Info field are reserved (Sec. 9.3.1.22.5 of 802.11ax)
394 auto staIt = staList.find(userInfo.GetAid12());
395 NS_ASSERT(staIt != staList.cend());
396 AddUserInfoToMuRts(protection->muRts, txWidth, staIt->second);
397 const auto isProtected = protectedStas.contains(staIt->second);
398 allProtected = allProtected && isProtected;
399
400 isUnprotectedEmlsrDst =
401 isUnprotectedEmlsrDst ||
402 (!isProtected && GetWifiRemoteStationManager()->GetEmlsrEnabled(staIt->second));
403 }
404
405 bool needMuRts =
406 (m_sendMuRts && !allProtected && (!m_singleRtsPerTxop || protectedStas.empty())) ||
407 isUnprotectedEmlsrDst;
408
409 // if we are sending a BSRP TF and SkipMuRtsBeforeBsrpTf is true, do not use MU-RTS (even in
410 // case of unprotected EMLSR, because the BSRP TF is an ICF)
411 needMuRts = needMuRts && (!m_skipMuRtsBeforeBsrp || !trigger.IsBsrp());
412
413 if (!needMuRts)
414 {
415 // No protection needed
416 return std::make_unique<WifiNoProtection>();
417 }
418
419 // compute the TXVECTOR to use to send the MU-RTS Trigger Frame
420 protection->muRtsTxVector =
421 GetWifiRemoteStationManager()->GetRtsTxVector(mpdu->GetHeader().GetAddr1(), txWidth);
422 // The transmitter of an MU-RTS Trigger frame shall not request a non-AP STA to send
423 // a CTS frame response in a 20 MHz channel that is not occupied by the PPDU that
424 // contains the MU-RTS Trigger frame. (Sec. 26.2.6.2 of 802.11ax)
425 protection->muRtsTxVector.SetChannelWidth(txWidth);
426 // OFDM is needed to transmit the PPDU over a bandwidth that is a multiple of 20 MHz
427 const auto modulation = protection->muRtsTxVector.GetModulationClass();
428 if (modulation == WIFI_MOD_CLASS_DSSS || modulation == WIFI_MOD_CLASS_HR_DSSS)
429 {
430 protection->muRtsTxVector.SetMode(ErpOfdmPhy::GetErpOfdmRate6Mbps());
431 }
432 if (isUnprotectedEmlsrDst)
433 {
434 // This MU-RTS is an ICF for some EMLSR client
435 auto ehtFem = StaticCast<EhtFrameExchangeManager>(m_mac->GetFrameExchangeManager(m_linkId));
436 ehtFem->SetIcfPaddingAndTxVector(protection->muRts, protection->muRtsTxVector);
437 }
438
439 return protection;
440}
441
442} // namespace ns3
AttributeValue implementation for Boolean.
Definition boolean.h:26
Headers for Trigger frames.
bool IsBsrp() const
Check if this is a Buffer Status Report Poll Trigger frame.
std::size_t GetNUserInfoFields() const
Get the number of User Info fields in this Trigger Frame.
void SetType(TriggerFrameType type)
Set the Trigger frame type.
MHz_u GetUlBandwidth() const
Get the bandwidth of the solicited HE/EHT TB PPDU.
TriggerFrameVariant GetVariant() const
Get the Common Info field variant.
void SetVariant(TriggerFrameVariant variant)
Set the Common Info field variant.
void SetUlBandwidth(MHz_u bw)
Set the bandwidth of the solicited HE/EHT TB PPDU.
static WifiMode GetErpOfdmRate6Mbps()
Return a WifiMode for ERP-OFDM at 6 Mbps.
Smart pointer class similar to boost::intrusive_ptr.
Definition ptr.h:70
a unique identifier for an interface.
Definition type-id.h:50
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:999
WifiDefaultProtectionManager is the default protection manager, which selects the protection method f...
std::unique_ptr< WifiProtection > TryAddMpdu(Ptr< const WifiMpdu > mpdu, const WifiTxParameters &txParams) override
Determine the protection method to use if the given MPDU is added to the current frame.
bool m_sendMuRts
true for sending an MU-RTS to protect DL MU PPDUs
bool m_skipMuRtsBeforeBsrp
whether to skip MU-RTS before BSRP TF
std::unique_ptr< WifiProtection > TryAggregateMsdu(Ptr< const WifiMpdu > msdu, const WifiTxParameters &txParams) override
Determine the protection method to use if the given MSDU is aggregated to the current frame.
bool m_singleRtsPerTxop
true for using protection only once in a TXOP
virtual std::unique_ptr< WifiProtection > TryUlMuTransmission(Ptr< const WifiMpdu > mpdu, const WifiTxParameters &txParams)
Calculate the protection method for the UL MU transmission solicited by the given Trigger Frame.
virtual std::unique_ptr< WifiProtection > GetPsduProtection(const WifiMacHeader &hdr, const WifiTxParameters &txParams) const
Select the protection method for a single PSDU.
virtual std::unique_ptr< WifiProtection > TryAddMpduToMuPpdu(Ptr< const WifiMpdu > mpdu, const WifiTxParameters &txParams)
Calculate the protection method to use if the given MPDU is added to the current DL MU PPDU (represen...
Implements the IEEE 802.11 MAC header.
Mac48Address GetAddr1() const
Return the address in the Address 1 field.
bool IsRetry() const
Return if the Retry bit is set.
uint8_t GetFragmentNumber() const
Return the fragment number of the header.
Ptr< WifiMac > m_mac
MAC which is using this Protection Manager.
void AddUserInfoToMuRts(CtrlTriggerHeader &muRts, MHz_u txWidth, const Mac48Address &receiver) const
Add a User Info field to the given MU-RTS Trigger Frame to solicit a CTS from the station with the gi...
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager() const
uint8_t m_linkId
ID of the link this Protection Manager is operating on.
This class stores the TX parameters (TX vector, protection mechanism, acknowledgment mechanism,...
const PsduInfoMap & GetPsduInfoMap() const
Get a const reference to the map containing information about PSDUs.
std::unique_ptr< WifiProtection > m_protection
protection method
bool LastAddedIsFirstMpdu(Mac48Address receiver) const
Check if the last added MPDU is the first MPDU for the given receiver.
WifiTxVector m_txVector
TXVECTOR of the frame being prepared.
void SetChannelWidth(MHz_u channelWidth)
Sets the selected channelWidth.
WifiModulationClass GetModulationClass() const
Get the modulation class specified by this TXVECTOR.
MHz_u GetChannelWidth() const
void SetMode(WifiMode mode)
Sets the selected payload transmission mode.
const std::vector< bool > & GetInactiveSubchannels() const
Get the 20 MHz subchannels that are punctured.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition boolean.cc:113
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition boolean.h:70
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition abort.h:97
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:194
#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.
Definition object-base.h:35
@ AP
Definition wifi-mac.h:60
@ WIFI_MOD_CLASS_HR_DSSS
HR/DSSS (Clause 16).
@ WIFI_MOD_CLASS_DSSS
DSSS (Clause 15).
Every class exported by the ns3 library is enclosed in the ns3 namespace.
double MHz_u
MHz weak type.
Definition wifi-units.h:31
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:605
Ptr< T1 > StaticCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:612
WifiMuRtsCtsProtection specifies that MU-RTS/CTS protection method is used.
CtrlTriggerHeader muRts
MU-RTS.
WifiTxVector muRtsTxVector
MU-RTS TXVECTOR.