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
29NS_OBJECT_ENSURE_REGISTERED(WifiDefaultProtectionManager);
30
31TypeId
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 // Call a separate method that handles MU-RTS/CTS protection in case of DL MU PPDU containing
77 // more than one PSDU or in case the MPDU being added is addressed to an EMLSR client or in
78 // case the protection method is already MU-RTS/CTS.
79 const auto& psduInfoMap = txParams.GetPsduInfoMap();
80 auto dlMuPpdu = txParams.m_txVector.IsDlMu() && psduInfoMap.size() > 1;
81 const auto& hdr = mpdu->GetHeader();
82 auto isEmlsrDestination = GetWifiRemoteStationManager()->GetEmlsrEnabled(hdr.GetAddr1());
83
84 if (dlMuPpdu || isEmlsrDestination ||
85 (txParams.m_protection && txParams.m_protection->method == WifiProtection::MU_RTS_CTS))
86 {
87 return TryAddMpduToMuPpdu(mpdu, txParams);
88 }
89
90 // No protection for TB PPDUs (the soliciting Trigger Frame can be protected by an MU-RTS)
91 if (txParams.m_txVector.IsUlMu())
92 {
93 if (txParams.m_protection)
94 {
95 NS_ASSERT(txParams.m_protection->method == WifiProtection::NONE);
96 return nullptr;
97 }
98 return std::make_unique<WifiNoProtection>();
99 }
100
101 // if this is a Trigger Frame, call a separate method
102 if (hdr.IsTrigger())
103 {
104 return TryUlMuTransmission(mpdu, txParams);
105 }
106
107 // if the current protection method (if any) is already RTS/CTS or CTS-to-Self,
108 // it will not change by adding an MPDU
109 if (txParams.m_protection && (txParams.m_protection->method == WifiProtection::RTS_CTS ||
110 txParams.m_protection->method == WifiProtection::CTS_TO_SELF))
111 {
112 return nullptr;
113 }
114
115 // if a protection method is set, it must be NONE
116 NS_ASSERT(!txParams.m_protection || txParams.m_protection->method == WifiProtection::NONE);
117
118 std::unique_ptr<WifiProtection> protection;
119 protection = GetPsduProtection(hdr, txParams);
120
121 // return the newly computed method if none was set or it is not NONE
122 if (!txParams.m_protection || protection->method != WifiProtection::NONE)
123 {
124 return protection;
125 }
126 // the protection method has not changed
127 return nullptr;
128}
129
130std::unique_ptr<WifiProtection>
132 const WifiTxParameters& txParams)
133{
134 NS_LOG_FUNCTION(this << *msdu << &txParams);
135
136 // if the current protection method is already RTS/CTS, CTS-to-Self or MU-RTS/CTS,
137 // it will not change by aggregating an MSDU
138 NS_ASSERT(txParams.m_protection);
139 if (txParams.m_protection->method == WifiProtection::RTS_CTS ||
140 txParams.m_protection->method == WifiProtection::CTS_TO_SELF ||
141 txParams.m_protection->method == WifiProtection::MU_RTS_CTS)
142 {
143 return nullptr;
144 }
145
146 NS_ASSERT(txParams.m_protection->method == WifiProtection::NONE);
147
148 // No protection for TB PPDUs and DL MU PPDUs containing more than one PSDU
149 if (txParams.m_txVector.IsUlMu() ||
150 (txParams.m_txVector.IsDlMu() && txParams.GetPsduInfoMap().size() > 1))
151 {
152 return nullptr;
153 }
154
155 std::unique_ptr<WifiProtection> protection;
156 protection = GetPsduProtection(msdu->GetHeader(), txParams);
157
158 // the protection method may still be none
159 if (protection->method == WifiProtection::NONE)
160 {
161 return nullptr;
162 }
163
164 // the protection method has changed
165 return protection;
166}
167
168std::unique_ptr<WifiProtection>
170 const WifiTxParameters& txParams) const
171{
172 NS_LOG_FUNCTION(this << hdr << &txParams);
173
174 // a non-initial fragment does not need to be protected, unless it is being retransmitted
175 if (hdr.GetFragmentNumber() > 0 && !hdr.IsRetry())
176 {
177 return std::make_unique<WifiNoProtection>();
178 }
179
180 // no need to use protection if destination already received an RTS in this TXOP or
181 // SingleRtsPerTxop is true and a protection mechanism has been already used in this TXOP
182 if (const auto& protectedStas = m_mac->GetFrameExchangeManager(m_linkId)->GetProtectedStas();
183 protectedStas.contains(hdr.GetAddr1()) || (m_singleRtsPerTxop && !protectedStas.empty()))
184 {
185 return std::make_unique<WifiNoProtection>();
186 }
187
188 // when an EMLSR client starts an UL TXOP on a link while the MediumSyncDelay timer is running
189 // or on a link on which the main PHY is not operating, it needs to send an RTS frame
190 bool emlsrNeedRts = false;
191
192 if (auto staMac = DynamicCast<StaWifiMac>(m_mac))
193 {
194 auto emlsrManager = staMac->GetEmlsrManager();
195
196 emlsrNeedRts = emlsrManager && staMac->IsEmlsrLink(m_linkId) &&
197 (emlsrManager->GetElapsedMediumSyncDelayTimer(m_linkId) ||
198 m_mac->GetLinkForPhy(emlsrManager->GetMainPhyId()) != m_linkId);
199 }
200
201 // check if RTS/CTS is needed
202 if (emlsrNeedRts || GetWifiRemoteStationManager()->NeedRts(hdr, txParams))
203 {
204 auto protection = std::make_unique<WifiRtsCtsProtection>();
205 protection->rtsTxVector =
206 GetWifiRemoteStationManager()->GetRtsTxVector(hdr.GetAddr1(),
207 txParams.m_txVector.GetChannelWidth());
208 protection->ctsTxVector =
209 GetWifiRemoteStationManager()->GetCtsTxVector(hdr.GetAddr1(),
210 protection->rtsTxVector.GetMode());
211 return protection;
212 }
213
214 // check if CTS-to-Self is needed
215 if (GetWifiRemoteStationManager()->NeedCtsToSelf(txParams.m_txVector, hdr))
216 {
217 auto protection = std::make_unique<WifiCtsToSelfProtection>();
218 protection->ctsTxVector = GetWifiRemoteStationManager()->GetCtsToSelfTxVector();
219 return protection;
220 }
221
222 return std::make_unique<WifiNoProtection>();
223}
224
225std::unique_ptr<WifiProtection>
227 const WifiTxParameters& txParams)
228{
229 NS_LOG_FUNCTION(this << *mpdu << &txParams);
230
231 auto receiver = mpdu->GetHeader().GetAddr1();
232 const auto& psduInfoMap = txParams.GetPsduInfoMap();
233 auto dlMuPpdu = txParams.m_txVector.IsDlMu() && psduInfoMap.size() > 1;
234 auto isEmlsrDestination = GetWifiRemoteStationManager()->GetEmlsrEnabled(receiver);
235 NS_ASSERT(
236 dlMuPpdu || isEmlsrDestination ||
237 (txParams.m_protection && txParams.m_protection->method == WifiProtection::MU_RTS_CTS));
238
239 const auto& protectedStas = m_mac->GetFrameExchangeManager(m_linkId)->GetProtectedStas();
240 const auto isProtected = protectedStas.contains(receiver);
241 bool needMuRts =
242 (txParams.m_protection && txParams.m_protection->method == WifiProtection::MU_RTS_CTS) ||
243 (dlMuPpdu && m_sendMuRts && !isProtected &&
244 (!m_singleRtsPerTxop || protectedStas.empty())) ||
245 (isEmlsrDestination && !isProtected);
246
247 if (!needMuRts)
248 {
249 // No protection needed
250 if (txParams.m_protection && txParams.m_protection->method == WifiProtection::NONE)
251 {
252 return nullptr;
253 }
254 return std::make_unique<WifiNoProtection>();
255 }
256
257 WifiMuRtsCtsProtection* protection = nullptr;
258 if (txParams.m_protection && txParams.m_protection->method == WifiProtection::MU_RTS_CTS)
259 {
260 protection = static_cast<WifiMuRtsCtsProtection*>(txParams.m_protection.get());
261 }
262
263 if (txParams.LastAddedIsFirstMpdu(receiver))
264 {
265 // we get here if this is the first MPDU for this receiver.
266 NS_ABORT_MSG_IF(m_mac->GetTypeOfStation() != AP, "HE APs only can send DL MU PPDUs");
267 auto modClass = txParams.m_txVector.GetModulationClass();
268 auto txWidth = modClass == WIFI_MOD_CLASS_DSSS || modClass == WIFI_MOD_CLASS_HR_DSSS
269 ? MHz_u{20}
270 : txParams.m_txVector.GetChannelWidth();
271
272 if (protection != nullptr)
273 {
274 // txParams.m_protection points to an existing WifiMuRtsCtsProtection object.
275 // We have to return a copy of this object including the needed changes
276 protection = new WifiMuRtsCtsProtection(*protection);
277
278 // Add a User Info field for the new receiver
279 // The UL HE-MCS, UL FEC Coding Type, UL DCM, SS Allocation and UL Target RSSI fields
280 // in the User Info field are reserved (Sec. 9.3.1.22.5 of 802.11ax)
281 AddUserInfoToMuRts(protection->muRts, txWidth, receiver);
282 }
283 else
284 {
285 // we have to create a new WifiMuRtsCtsProtection object
286 protection = new WifiMuRtsCtsProtection;
287
288 // initialize the MU-RTS Trigger Frame
289 // The UL Length, GI And HE-LTF Type, MU-MIMO HE-LTF Mode, Number Of HE-LTF Symbols,
290 // UL STBC, LDPC Extra Symbol Segment, AP TX Power, Pre-FEC Padding Factor,
291 // PE Disambiguity, UL Spatial Reuse, Doppler and UL HE-SIG-A2 Reserved subfields in
292 // the Common Info field are reserved. (Sec. 9.3.1.22.5 of 802.11ax)
294 protection->muRts.SetUlBandwidth(txWidth);
295
296 // Add a User Info field for each of the receivers already in the TX params
297 for (const auto& [address, info] : txParams.GetPsduInfoMap())
298 {
299 AddUserInfoToMuRts(protection->muRts, txWidth, address);
300 }
301
302 // compute the TXVECTOR to use to send the MU-RTS Trigger Frame
303 protection->muRtsTxVector =
304 GetWifiRemoteStationManager()->GetRtsTxVector(receiver, txWidth);
305 // The transmitter of an MU-RTS Trigger frame shall not request a non-AP STA to send
306 // a CTS frame response in a 20 MHz channel that is not occupied by the PPDU that
307 // contains the MU-RTS Trigger frame. (Sec. 26.2.6.2 of 802.11ax)
308 protection->muRtsTxVector.SetChannelWidth(txWidth);
309 // OFDM is needed to transmit the PPDU over a bandwidth that is a multiple of 20 MHz
310 const auto modulation = protection->muRtsTxVector.GetModulationClass();
311 if (modulation == WIFI_MOD_CLASS_DSSS || modulation == WIFI_MOD_CLASS_HR_DSSS)
312 {
314 }
315 }
316
317 if (isEmlsrDestination && !isProtected)
318 {
319 // This MU-RTS is an ICF for some EMLSR client
320 auto ehtFem =
321 StaticCast<EhtFrameExchangeManager>(m_mac->GetFrameExchangeManager(m_linkId));
322 ehtFem->SetIcfPaddingAndTxVector(protection->muRts, protection->muRtsTxVector);
323 }
324
325 return std::unique_ptr<WifiMuRtsCtsProtection>(protection);
326 }
327
328 // an MPDU addressed to the same receiver has been already added
329 NS_ASSERT(protection != nullptr);
330
331 // no change is needed
332 return nullptr;
333}
334
335std::unique_ptr<WifiProtection>
337 const WifiTxParameters& txParams)
338{
339 NS_LOG_FUNCTION(this << *mpdu << &txParams);
340 NS_ASSERT(mpdu->GetHeader().IsTrigger());
341
342 CtrlTriggerHeader trigger;
343 mpdu->GetPacket()->PeekHeader(trigger);
344 NS_ASSERT(trigger.GetNUserInfoFields() > 0);
345 auto txWidth = trigger.GetUlBandwidth();
346
347 auto protection = std::make_unique<WifiMuRtsCtsProtection>();
348 // initialize the MU-RTS Trigger Frame
349 // The UL Length, GI And HE-LTF Type, MU-MIMO HE-LTF Mode, Number Of HE-LTF Symbols,
350 // UL STBC, LDPC Extra Symbol Segment, AP TX Power, Pre-FEC Padding Factor,
351 // PE Disambiguity, UL Spatial Reuse, Doppler and UL HE-SIG-A2 Reserved subfields in
352 // the Common Info field are reserved. (Sec. 9.3.1.22.5 of 802.11ax)
353 protection->muRts.SetType(TriggerFrameType::MU_RTS_TRIGGER);
354 protection->muRts.SetUlBandwidth(txWidth);
355
356 NS_ABORT_MSG_IF(m_mac->GetTypeOfStation() != AP, "HE APs only can send DL MU PPDUs");
357 const auto& staList = StaticCast<ApWifiMac>(m_mac)->GetStaList(m_linkId);
358
359 const auto& protectedStas = m_mac->GetFrameExchangeManager(m_linkId)->GetProtectedStas();
360 bool allProtected = true;
361 bool isUnprotectedEmlsrDst = false;
362
363 for (const auto& userInfo : trigger)
364 {
365 // Add a User Info field to the MU-RTS for this solicited station
366 // The UL HE-MCS, UL FEC Coding Type, UL DCM, SS Allocation and UL Target RSSI fields
367 // in the User Info field are reserved (Sec. 9.3.1.22.5 of 802.11ax)
368 auto staIt = staList.find(userInfo.GetAid12());
369 NS_ASSERT(staIt != staList.cend());
370 AddUserInfoToMuRts(protection->muRts, txWidth, staIt->second);
371 const auto isProtected = protectedStas.contains(staIt->second);
372 allProtected = allProtected && isProtected;
373
374 isUnprotectedEmlsrDst =
375 isUnprotectedEmlsrDst ||
376 (!isProtected && GetWifiRemoteStationManager()->GetEmlsrEnabled(staIt->second));
377 }
378
379 bool needMuRts =
380 (m_sendMuRts && !allProtected && (!m_singleRtsPerTxop || protectedStas.empty())) ||
381 isUnprotectedEmlsrDst;
382
383 // if we are sending a BSRP TF and SkipMuRtsBeforeBsrpTf is true, do not use MU-RTS (even in
384 // case of unprotected EMLSR, because the BSRP TF is an ICF)
385 needMuRts = needMuRts && (!m_skipMuRtsBeforeBsrp || !trigger.IsBsrp());
386
387 if (!needMuRts)
388 {
389 // No protection needed
390 return std::make_unique<WifiNoProtection>();
391 }
392
393 // compute the TXVECTOR to use to send the MU-RTS Trigger Frame
394 protection->muRtsTxVector =
395 GetWifiRemoteStationManager()->GetRtsTxVector(mpdu->GetHeader().GetAddr1(), txWidth);
396 // The transmitter of an MU-RTS Trigger frame shall not request a non-AP STA to send
397 // a CTS frame response in a 20 MHz channel that is not occupied by the PPDU that
398 // contains the MU-RTS Trigger frame. (Sec. 26.2.6.2 of 802.11ax)
399 protection->muRtsTxVector.SetChannelWidth(txWidth);
400 // OFDM is needed to transmit the PPDU over a bandwidth that is a multiple of 20 MHz
401 const auto modulation = protection->muRtsTxVector.GetModulationClass();
402 if (modulation == WIFI_MOD_CLASS_DSSS || modulation == WIFI_MOD_CLASS_HR_DSSS)
403 {
404 protection->muRtsTxVector.SetMode(ErpOfdmPhy::GetErpOfdmRate6Mbps());
405 }
406 if (isUnprotectedEmlsrDst)
407 {
408 // This MU-RTS is an ICF for some EMLSR client
409 auto ehtFem = StaticCast<EhtFrameExchangeManager>(m_mac->GetFrameExchangeManager(m_linkId));
410 ehtFem->SetIcfPaddingAndTxVector(protection->muRts, protection->muRtsTxVector);
411 }
412
413 return protection;
414}
415
416} // 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 TB PPDU.
void SetUlBandwidth(MHz_u bw)
Set the bandwidth of the solicited HE TB PPDU.
static WifiMode GetErpOfdmRate6Mbps()
Return a WifiMode for ERP-OFDM at 6 Mbps.
Smart pointer class similar to boost::intrusive_ptr.
a unique identifier for an interface.
Definition type-id.h:49
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
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.
WifiProtectionManager is an abstract base class.
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.
#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:191
#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.
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:580
Ptr< T1 > StaticCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:587
WifiMuRtsCtsProtection specifies that MU-RTS/CTS protection method is used.
CtrlTriggerHeader muRts
MU-RTS.
WifiTxVector muRtsTxVector
MU-RTS TXVECTOR.