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