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()->GetUseNonErpProtection() &&
216 GetWifiRemoteStationManager()->NeedCtsToSelf(txParams.m_txVector))
217 {
218 auto protection = std::make_unique<WifiCtsToSelfProtection>();
219 protection->ctsTxVector = GetWifiRemoteStationManager()->GetCtsToSelfTxVector();
220 return protection;
221 }
222
223 return std::make_unique<WifiNoProtection>();
224}
225
226std::unique_ptr<WifiProtection>
228 const WifiTxParameters& txParams)
229{
230 NS_LOG_FUNCTION(this << *mpdu << &txParams);
231
232 auto receiver = mpdu->GetHeader().GetAddr1();
233 const auto& psduInfoMap = txParams.GetPsduInfoMap();
234 auto dlMuPpdu = txParams.m_txVector.IsDlMu() && psduInfoMap.size() > 1;
235 auto isEmlsrDestination = GetWifiRemoteStationManager()->GetEmlsrEnabled(receiver);
236 NS_ASSERT(
237 dlMuPpdu || isEmlsrDestination ||
238 (txParams.m_protection && txParams.m_protection->method == WifiProtection::MU_RTS_CTS));
239
240 const auto& protectedStas = m_mac->GetFrameExchangeManager(m_linkId)->GetProtectedStas();
241 const auto isProtected = protectedStas.contains(receiver);
242 bool needMuRts =
243 (txParams.m_protection && txParams.m_protection->method == WifiProtection::MU_RTS_CTS) ||
244 (dlMuPpdu && m_sendMuRts && !isProtected &&
245 (!m_singleRtsPerTxop || protectedStas.empty())) ||
246 (isEmlsrDestination && !isProtected);
247
248 if (!needMuRts)
249 {
250 // No protection needed
251 if (txParams.m_protection && txParams.m_protection->method == WifiProtection::NONE)
252 {
253 return nullptr;
254 }
255 return std::make_unique<WifiNoProtection>();
256 }
257
258 WifiMuRtsCtsProtection* protection = nullptr;
259 if (txParams.m_protection && txParams.m_protection->method == WifiProtection::MU_RTS_CTS)
260 {
261 protection = static_cast<WifiMuRtsCtsProtection*>(txParams.m_protection.get());
262 }
263
264 if (txParams.LastAddedIsFirstMpdu(receiver))
265 {
266 // we get here if this is the first MPDU for this receiver.
267 NS_ABORT_MSG_IF(m_mac->GetTypeOfStation() != AP, "HE APs only can send DL MU PPDUs");
268 auto apMac = StaticCast<ApWifiMac>(m_mac);
269 auto modClass = txParams.m_txVector.GetModulationClass();
270 auto txWidth = modClass == WIFI_MOD_CLASS_DSSS || modClass == WIFI_MOD_CLASS_HR_DSSS
271 ? 20
272 : txParams.m_txVector.GetChannelWidth();
273
274 if (protection != nullptr)
275 {
276 // txParams.m_protection points to an existing WifiMuRtsCtsProtection object.
277 // We have to return a copy of this object including the needed changes
278 protection = new WifiMuRtsCtsProtection(*protection);
279
280 // Add a User Info field for the new receiver
281 // The UL HE-MCS, UL FEC Coding Type, UL DCM, SS Allocation and UL Target RSSI fields
282 // in the User Info field are reserved (Sec. 9.3.1.22.5 of 802.11ax)
283 AddUserInfoToMuRts(protection->muRts, txWidth, receiver);
284 }
285 else
286 {
287 // we have to create a new WifiMuRtsCtsProtection object
288 protection = new WifiMuRtsCtsProtection;
289
290 // initialize the MU-RTS Trigger Frame
291 // The UL Length, GI And HE-LTF Type, MU-MIMO HE-LTF Mode, Number Of HE-LTF Symbols,
292 // UL STBC, LDPC Extra Symbol Segment, AP TX Power, Pre-FEC Padding Factor,
293 // PE Disambiguity, UL Spatial Reuse, Doppler and UL HE-SIG-A2 Reserved subfields in
294 // the Common Info field are reserved. (Sec. 9.3.1.22.5 of 802.11ax)
296 protection->muRts.SetUlBandwidth(txWidth);
297
298 // Add a User Info field for each of the receivers already in the TX params
299 for (const auto& [address, info] : txParams.GetPsduInfoMap())
300 {
301 AddUserInfoToMuRts(protection->muRts, txWidth, address);
302 }
303
304 // compute the TXVECTOR to use to send the MU-RTS Trigger Frame
305 protection->muRtsTxVector =
306 GetWifiRemoteStationManager()->GetRtsTxVector(receiver, txWidth);
307 // The transmitter of an MU-RTS Trigger frame shall not request a non-AP STA to send
308 // a CTS frame response in a 20 MHz channel that is not occupied by the PPDU that
309 // contains the MU-RTS Trigger frame. (Sec. 26.2.6.2 of 802.11ax)
310 protection->muRtsTxVector.SetChannelWidth(txWidth);
311 // OFDM is needed to transmit the PPDU over a bandwidth that is a multiple of 20 MHz
312 const auto modulation = protection->muRtsTxVector.GetModulationClass();
313 if (modulation == WIFI_MOD_CLASS_DSSS || modulation == WIFI_MOD_CLASS_HR_DSSS)
314 {
316 }
317 }
318
319 if (isEmlsrDestination && !isProtected)
320 {
321 // This MU-RTS is an ICF for some EMLSR client
322 auto ehtFem =
323 StaticCast<EhtFrameExchangeManager>(m_mac->GetFrameExchangeManager(m_linkId));
324 ehtFem->SetIcfPaddingAndTxVector(protection->muRts, protection->muRtsTxVector);
325 }
326
327 return std::unique_ptr<WifiMuRtsCtsProtection>(protection);
328 }
329
330 // an MPDU addressed to the same receiver has been already added
331 NS_ASSERT(protection != nullptr);
332
333 // no change is needed
334 return nullptr;
335}
336
337std::unique_ptr<WifiProtection>
339 const WifiTxParameters& txParams)
340{
341 NS_LOG_FUNCTION(this << *mpdu << &txParams);
342 NS_ASSERT(mpdu->GetHeader().IsTrigger());
343
344 CtrlTriggerHeader trigger;
345 mpdu->GetPacket()->PeekHeader(trigger);
346 NS_ASSERT(trigger.GetNUserInfoFields() > 0);
347 auto txWidth = trigger.GetUlBandwidth();
348
349 auto protection = std::make_unique<WifiMuRtsCtsProtection>();
350 // initialize the MU-RTS Trigger Frame
351 // The UL Length, GI And HE-LTF Type, MU-MIMO HE-LTF Mode, Number Of HE-LTF Symbols,
352 // UL STBC, LDPC Extra Symbol Segment, AP TX Power, Pre-FEC Padding Factor,
353 // PE Disambiguity, UL Spatial Reuse, Doppler and UL HE-SIG-A2 Reserved subfields in
354 // the Common Info field are reserved. (Sec. 9.3.1.22.5 of 802.11ax)
355 protection->muRts.SetType(TriggerFrameType::MU_RTS_TRIGGER);
356 protection->muRts.SetUlBandwidth(txWidth);
357
358 NS_ABORT_MSG_IF(m_mac->GetTypeOfStation() != AP, "HE APs only can send DL MU PPDUs");
359 const auto& staList = StaticCast<ApWifiMac>(m_mac)->GetStaList(m_linkId);
360
361 const auto& protectedStas = m_mac->GetFrameExchangeManager(m_linkId)->GetProtectedStas();
362 bool allProtected = true;
363 bool isUnprotectedEmlsrDst = false;
364
365 for (const auto& userInfo : trigger)
366 {
367 // Add a User Info field to the MU-RTS for this solicited station
368 // The UL HE-MCS, UL FEC Coding Type, UL DCM, SS Allocation and UL Target RSSI fields
369 // in the User Info field are reserved (Sec. 9.3.1.22.5 of 802.11ax)
370 auto staIt = staList.find(userInfo.GetAid12());
371 NS_ASSERT(staIt != staList.cend());
372 AddUserInfoToMuRts(protection->muRts, txWidth, staIt->second);
373 const auto isProtected = protectedStas.contains(staIt->second);
374 allProtected = allProtected && isProtected;
375
376 isUnprotectedEmlsrDst =
377 isUnprotectedEmlsrDst ||
378 (!isProtected && GetWifiRemoteStationManager()->GetEmlsrEnabled(staIt->second));
379 }
380
381 bool needMuRts =
382 (m_sendMuRts && !allProtected && (!m_singleRtsPerTxop || protectedStas.empty())) ||
383 isUnprotectedEmlsrDst;
384
385 // if we are sending a BSRP TF and SkipMuRtsBeforeBsrpTf is true, do not use MU-RTS (even in
386 // case of unprotected EMLSR, because the BSRP TF is an ICF)
387 needMuRts = needMuRts && (!m_skipMuRtsBeforeBsrp || !trigger.IsBsrp());
388
389 if (!needMuRts)
390 {
391 // No protection needed
392 return std::make_unique<WifiNoProtection>();
393 }
394
395 // compute the TXVECTOR to use to send the MU-RTS Trigger Frame
396 protection->muRtsTxVector =
397 GetWifiRemoteStationManager()->GetRtsTxVector(mpdu->GetHeader().GetAddr1(), txWidth);
398 // The transmitter of an MU-RTS Trigger frame shall not request a non-AP STA to send
399 // a CTS frame response in a 20 MHz channel that is not occupied by the PPDU that
400 // contains the MU-RTS Trigger frame. (Sec. 26.2.6.2 of 802.11ax)
401 protection->muRtsTxVector.SetChannelWidth(txWidth);
402 // OFDM is needed to transmit the PPDU over a bandwidth that is a multiple of 20 MHz
403 const auto modulation = protection->muRtsTxVector.GetModulationClass();
404 if (modulation == WIFI_MOD_CLASS_DSSS || modulation == WIFI_MOD_CLASS_HR_DSSS)
405 {
406 protection->muRtsTxVector.SetMode(ErpOfdmPhy::GetErpOfdmRate6Mbps());
407 }
408 if (isUnprotectedEmlsrDst)
409 {
410 // This MU-RTS is an ICF for some EMLSR client
411 auto ehtFem = StaticCast<EhtFrameExchangeManager>(m_mac->GetFrameExchangeManager(m_linkId));
412 ehtFem->SetIcfPaddingAndTxVector(protection->muRts, protection->muRtsTxVector);
413 }
414
415 return protection;
416}
417
418} // 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:48
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:59
@ 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.