A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
rr-multi-user-scheduler.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 "he-configuration.h"
12#include "he-phy.h"
13
14#include "ns3/eht-frame-exchange-manager.h"
15#include "ns3/log.h"
16#include "ns3/wifi-acknowledgment.h"
17#include "ns3/wifi-mac-queue.h"
18#include "ns3/wifi-protection.h"
19#include "ns3/wifi-psdu.h"
20
21#include <algorithm>
22#include <numeric>
23
24namespace ns3
25{
26
27NS_LOG_COMPONENT_DEFINE("RrMultiUserScheduler");
28
29NS_OBJECT_ENSURE_REGISTERED(RrMultiUserScheduler);
30
31TypeId
33{
34 static TypeId tid =
35 TypeId("ns3::RrMultiUserScheduler")
37 .SetGroupName("Wifi")
38 .AddConstructor<RrMultiUserScheduler>()
39 .AddAttribute("NStations",
40 "The maximum number of stations that can be granted an RU in a DL MU "
41 "OFDMA transmission",
45 .AddAttribute("EnableTxopSharing",
46 "If enabled, allow A-MPDUs of different TIDs in a DL MU PPDU.",
47 BooleanValue(true),
50 .AddAttribute("ForceDlOfdma",
51 "If enabled, return DL_MU_TX even if no DL MU PPDU could be built.",
52 BooleanValue(false),
55 .AddAttribute("EnableUlOfdma",
56 "If enabled, return UL_MU_TX if DL_MU_TX was returned the previous time.",
57 BooleanValue(true),
60 .AddAttribute("EnableBsrp",
61 "If enabled, send a BSRP Trigger Frame before an UL MU transmission.",
62 BooleanValue(true),
65 .AddAttribute(
66 "UlPsduSize",
67 "The default size in bytes of the solicited PSDU (to be sent in a TB PPDU)",
68 UintegerValue(500),
71 .AddAttribute("UseCentral26TonesRus",
72 "If enabled, central 26-tone RUs are allocated, too, when the "
73 "selected RU type is at least 52 tones.",
74 BooleanValue(false),
77 .AddAttribute(
78 "MaxCredits",
79 "Maximum amount of credits a station can have. When transmitting a DL MU PPDU, "
80 "the amount of credits received by each station equals the TX duration (in "
81 "microseconds) divided by the total number of stations. Stations that are the "
82 "recipient of the DL MU PPDU have to pay a number of credits equal to the TX "
83 "duration (in microseconds) times the allocated bandwidth share",
87 return tid;
88}
89
94
99
100void
102{
103 NS_LOG_FUNCTION(this);
105 m_apMac->TraceConnectWithoutContext(
106 "AssociatedSta",
108 m_apMac->TraceConnectWithoutContext(
109 "DeAssociatedSta",
111 for (const auto& ac : wifiAcList)
112 {
113 m_staListDl.insert({ac.first, {}});
114 }
116}
117
118void
120{
121 NS_LOG_FUNCTION(this);
122 m_staListDl.clear();
123 m_staListUl.clear();
124 m_candidates.clear();
126 m_apMac->TraceDisconnectWithoutContext(
127 "AssociatedSta",
129 m_apMac->TraceDisconnectWithoutContext(
130 "DeAssociatedSta",
133}
134
137{
138 NS_LOG_FUNCTION(this);
139
141
142 if (mpdu && !m_apMac->GetHeSupported(mpdu->GetHeader().GetAddr1()))
143 {
144 return SU_TX;
145 }
146
150 {
151 TxFormat txFormat = TrySendingBsrpTf();
152
153 if (txFormat != DL_MU_TX)
154 {
155 return txFormat;
156 }
157 }
160 {
161 TxFormat txFormat = TrySendingBasicTf();
162
163 if (txFormat != DL_MU_TX)
164 {
165 return txFormat;
166 }
167 }
168
169 return TrySendingDlMuPpdu();
170}
171
173RrMultiUserScheduler::GetTxVectorForUlMu(std::function<bool(const MasterInfo&)> canBeSolicited)
174{
175 NS_LOG_FUNCTION(this);
176
177 // determine RUs to allocate to stations
178 auto count = std::min<std::size_t>(m_nStations, m_staListUl.size());
179 std::size_t nCentral26TonesRus;
180 HeRu::GetEqualSizedRusForStations(m_allowedWidth, count, nCentral26TonesRus);
181 NS_ASSERT(count >= 1);
182
184 {
185 nCentral26TonesRus = 0;
186 }
187
188 Ptr<HeConfiguration> heConfiguration = m_apMac->GetHeConfiguration();
189 NS_ASSERT(heConfiguration);
190
191 WifiTxVector txVector;
194 txVector.SetGuardInterval(heConfiguration->GetGuardInterval());
195 txVector.SetBssColor(heConfiguration->m_bssColor);
196
197 // iterate over the associated stations until an enough number of stations is identified
198 auto staIt = m_staListUl.begin();
199 m_candidates.clear();
200
201 while (staIt != m_staListUl.end() &&
202 txVector.GetHeMuUserInfoMap().size() <
203 std::min<std::size_t>(m_nStations, count + nCentral26TonesRus))
204 {
205 NS_LOG_DEBUG("Next candidate STA (MAC=" << staIt->address << ", AID=" << staIt->aid << ")");
206
207 if (!canBeSolicited(*staIt))
208 {
209 NS_LOG_DEBUG("Skipping station based on provided function object");
210 staIt++;
211 continue;
212 }
213
214 if (txVector.GetPreambleType() == WIFI_PREAMBLE_EHT_TB &&
215 !m_apMac->GetEhtSupported(staIt->address))
216 {
218 "Skipping non-EHT STA because this Trigger Frame is only soliciting EHT STAs");
219 staIt++;
220 continue;
221 }
222
223 uint8_t tid = 0;
224 while (tid < 8)
225 {
226 // check that a BA agreement is established with the receiver for the
227 // considered TID, since ack sequences for UL MU require block ack
228 if (m_apMac->GetBaAgreementEstablishedAsRecipient(staIt->address, tid))
229 {
230 break;
231 }
232 ++tid;
233 }
234 if (tid == 8)
235 {
236 NS_LOG_DEBUG("No Block Ack agreement established with " << staIt->address);
237 staIt++;
238 continue;
239 }
240
241 // if the first candidate STA is an EHT STA, we switch to soliciting EHT TB PPDUs
242 if (txVector.GetHeMuUserInfoMap().empty())
243 {
244 if (m_apMac->GetEhtSupported() && m_apMac->GetEhtSupported(staIt->address))
245 {
247 txVector.SetEhtPpduType(0);
248 }
249 // TODO otherwise, make sure the TX width does not exceed 160 MHz
250 }
251
252 // prepare the MAC header of a frame that would be sent to the candidate station,
253 // just for the purpose of retrieving the TXVECTOR used to transmit to that station
256 ->GetAffiliatedStaAddress(staIt->address)
257 .value_or(staIt->address));
258 hdr.SetAddr2(m_apMac->GetFrameExchangeManager(m_linkId)->GetAddress());
259 WifiTxVector suTxVector =
261 txVector.SetHeMuUserInfo(staIt->aid,
262 {HeRu::RuSpec(), // assigned later by FinalizeTxVector
263 suTxVector.GetMode().GetMcsValue(),
264 suTxVector.GetNss()});
265 m_candidates.emplace_back(staIt, nullptr);
266
267 // move to the next station in the list
268 staIt++;
269 }
270
271 if (txVector.GetHeMuUserInfoMap().empty())
272 {
273 NS_LOG_DEBUG("No suitable station");
274 return txVector;
275 }
276
277 FinalizeTxVector(txVector);
278 return txVector;
279}
280
281bool
283{
284 // check if station has setup the current link
285 if (!m_apMac->GetStaList(m_linkId).contains(info.aid))
286 {
287 NS_LOG_INFO("STA with AID " << info.aid << " has not setup link " << +m_linkId);
288 return false;
289 }
290
291 auto mldAddr = GetWifiRemoteStationManager(m_linkId)->GetMldAddress(info.address);
292
293 // remaining checks are for MLDs only
294 if (!mldAddr)
295 {
296 return true;
297 }
298
299 // check if at least one TID is mapped on the current link in the UL direction
300 bool mapped = false;
301 for (uint8_t tid = 0; tid < 8; ++tid)
302 {
303 if (m_apMac->TidMappedOnLink(*mldAddr, WifiDirection::UPLINK, tid, m_linkId))
304 {
305 mapped = true;
306 break;
307 }
308 }
309
310 if (!mapped)
311 {
312 NS_LOG_DEBUG("MLD " << *mldAddr << " has not mapped any TID on link " << +m_linkId);
313 return false;
314 }
315
316 // check if the station is an EMLSR client that is using another link
317 if (GetWifiRemoteStationManager(m_linkId)->GetEmlsrEnabled(info.address) &&
318 (m_apMac->GetTxBlockedOnLink(AC_BE,
319 {WIFI_QOSDATA_QUEUE, WIFI_UNICAST, *mldAddr, 0},
320 m_linkId,
322 m_apMac->GetTxBlockedOnLink(AC_BE,
323 {WIFI_QOSDATA_QUEUE, WIFI_UNICAST, *mldAddr, 0},
324 m_linkId,
326 {
327 NS_LOG_INFO("EMLSR client " << *mldAddr << " is using another link");
328 return false;
329 }
330
331 return true;
332}
333
336{
337 NS_LOG_FUNCTION(this);
338
339 if (m_staListUl.empty())
340 {
341 NS_LOG_DEBUG("No HE stations associated: return SU_TX");
342 return TxFormat::SU_TX;
343 }
344
345 auto txVector = GetTxVectorForUlMu(
346 std::bind(&RrMultiUserScheduler::CanSolicitStaInBsrpTf, this, std::placeholders::_1));
347
348 if (txVector.GetHeMuUserInfoMap().empty())
349 {
350 NS_LOG_DEBUG("No suitable station found");
351 return TxFormat::DL_MU_TX;
352 }
353
355 txVector.SetGuardInterval(m_trigger.GetGuardInterval());
356
357 auto item = GetTriggerFrame(m_trigger, m_linkId);
358 m_triggerMacHdr = item->GetHeader();
359
361 // set the TXVECTOR used to send the Trigger Frame
363 m_apMac->GetWifiRemoteStationManager(m_linkId)->GetRtsTxVector(m_triggerMacHdr.GetAddr1(),
365
366 // If this BSRP TF is an ICF, we need to add padding and adjust the TXVECTOR
367 if (auto ehtFem =
368 DynamicCast<EhtFrameExchangeManager>(m_apMac->GetFrameExchangeManager(m_linkId)))
369 {
370 auto prevPaddingSize = m_trigger.GetPaddingSize();
371 ehtFem->SetIcfPaddingAndTxVector(m_trigger, m_txParams.m_txVector);
372 // serialize again if padding has been added
373 if (m_trigger.GetPaddingSize() != prevPaddingSize)
374 {
375 auto packet = Create<Packet>();
376 packet->AddHeader(m_trigger);
377 item = Create<WifiMpdu>(packet, item->GetHeader());
378 }
379 }
380
381 if (!GetHeFem(m_linkId)->TryAddMpdu(item, m_txParams, m_availableTime))
382 {
383 // sending the BSRP Trigger Frame is not possible, hence return NO_TX. In
384 // this way, no transmission will occur now and the next time we will
385 // try again sending a BSRP Trigger Frame.
386 NS_LOG_DEBUG("Remaining TXOP duration is not enough for BSRP TF exchange");
387 return NO_TX;
388 }
389
390 // Compute the time taken by each station to transmit 8 QoS Null frames
391 Time qosNullTxDuration;
392 for (const auto& userInfo : m_trigger)
393 {
395 txVector,
396 m_apMac->GetWifiPhy(m_linkId)->GetPhyBand(),
397 userInfo.GetAid12());
398 qosNullTxDuration = Max(qosNullTxDuration, duration);
399 }
400
401 NS_ASSERT(m_txParams.m_txDuration.has_value());
403
404 if (m_availableTime != Time::Min())
405 {
406 // TryAddMpdu only considers the time to transmit the Trigger Frame
407 NS_ASSERT(m_txParams.m_protection && m_txParams.m_protection->protectionTime.has_value());
409 m_txParams.m_acknowledgment->acknowledgmentTime.has_value() &&
410 m_txParams.m_acknowledgment->acknowledgmentTime->IsZero());
411
412 if (*m_txParams.m_protection->protectionTime + *m_txParams.m_txDuration // BSRP TF tx time
413 + m_apMac->GetWifiPhy(m_linkId)->GetSifs() + qosNullTxDuration >
415 {
416 NS_LOG_DEBUG("Remaining TXOP duration is not enough for BSRP TF exchange");
417 return NO_TX;
418 }
419 }
420
421 uint16_t ulLength;
422 std::tie(ulLength, qosNullTxDuration) = HePhy::ConvertHeTbPpduDurationToLSigLength(
423 qosNullTxDuration,
425 m_apMac->GetWifiPhy(m_linkId)->GetPhyBand());
426 NS_LOG_DEBUG("Duration of QoS Null frames: " << qosNullTxDuration.As(Time::MS));
427 m_trigger.SetUlLength(ulLength);
428
429 return UL_MU_TX;
430}
431
432bool
434{
435 // in addition to the checks performed when sending a BSRP TF, also check if the station
436 // has reported a null queue size
437 if (!CanSolicitStaInBsrpTf(info))
438 {
439 return false;
440 }
441
442 return m_apMac->GetMaxBufferStatus(info.address) > 0;
443}
444
447{
448 NS_LOG_FUNCTION(this);
449
450 if (m_staListUl.empty())
451 {
452 NS_LOG_DEBUG("No HE stations associated: return SU_TX");
453 return TxFormat::SU_TX;
454 }
455
456 // check if an UL OFDMA transmission is possible after a DL OFDMA transmission
457 NS_ABORT_MSG_IF(m_ulPsduSize == 0, "The UlPsduSize attribute must be set to a non-null value");
458
459 auto txVector = GetTxVectorForUlMu(
460 std::bind(&RrMultiUserScheduler::CanSolicitStaInBasicTf, this, std::placeholders::_1));
461
462 if (txVector.GetHeMuUserInfoMap().empty())
463 {
464 NS_LOG_DEBUG("No suitable station found");
465 return TxFormat::DL_MU_TX;
466 }
467
468 uint32_t maxBufferSize = 0;
469
470 for (const auto& candidate : txVector.GetHeMuUserInfoMap())
471 {
472 auto address = m_apMac->GetMldOrLinkAddressByAid(candidate.first);
473 NS_ASSERT_MSG(address, "AID " << candidate.first << " not found");
474
475 uint8_t queueSize = m_apMac->GetMaxBufferStatus(*address);
476 if (queueSize == 255)
477 {
478 NS_LOG_DEBUG("Buffer status of station " << *address << " is unknown");
479 maxBufferSize = std::max(maxBufferSize, m_ulPsduSize);
480 }
481 else if (queueSize == 254)
482 {
483 NS_LOG_DEBUG("Buffer status of station " << *address << " is not limited");
484 maxBufferSize = 0xffffffff;
485 }
486 else
487 {
488 NS_LOG_DEBUG("Buffer status of station " << *address << " is " << +queueSize);
489 maxBufferSize = std::max(maxBufferSize, static_cast<uint32_t>(queueSize * 256));
490 }
491 }
492
493 if (maxBufferSize == 0)
494 {
495 return DL_MU_TX;
496 }
497
499 txVector.SetGuardInterval(m_trigger.GetGuardInterval());
500
501 auto item = GetTriggerFrame(m_trigger, m_linkId);
502 m_triggerMacHdr = item->GetHeader();
503
504 // compute the maximum amount of time that can be granted to stations.
505 // This value is limited by the max PPDU duration
506 Time maxDuration = GetPpduMaxTime(txVector.GetPreambleType());
507
509 // set the TXVECTOR used to send the Trigger Frame
511 m_apMac->GetWifiRemoteStationManager(m_linkId)->GetRtsTxVector(m_triggerMacHdr.GetAddr1(),
513
514 if (!GetHeFem(m_linkId)->TryAddMpdu(item, m_txParams, m_availableTime))
515 {
516 // an UL OFDMA transmission is not possible, hence return NO_TX. In
517 // this way, no transmission will occur now and the next time we will
518 // try again performing an UL OFDMA transmission.
519 NS_LOG_DEBUG("Remaining TXOP duration is not enough for UL MU exchange");
520 return NO_TX;
521 }
522
523 NS_ASSERT(m_txParams.m_txDuration.has_value());
525
526 if (m_availableTime != Time::Min())
527 {
528 // TryAddMpdu only considers the time to transmit the Trigger Frame
529 NS_ASSERT(m_txParams.m_protection && m_txParams.m_protection->protectionTime.has_value());
531 m_txParams.m_acknowledgment->acknowledgmentTime.has_value());
532
533 maxDuration = Min(maxDuration,
534 m_availableTime - *m_txParams.m_protection->protectionTime -
535 *m_txParams.m_txDuration - m_apMac->GetWifiPhy(m_linkId)->GetSifs() -
536 *m_txParams.m_acknowledgment->acknowledgmentTime);
537 if (maxDuration.IsNegative())
538 {
539 NS_LOG_DEBUG("Remaining TXOP duration is not enough for UL MU exchange");
540 return NO_TX;
541 }
542 }
543
544 // Compute the time taken by each station to transmit a frame of maxBufferSize size
545 Time bufferTxTime;
546 for (const auto& userInfo : m_trigger)
547 {
548 Time duration = WifiPhy::CalculateTxDuration(maxBufferSize,
549 txVector,
550 m_apMac->GetWifiPhy(m_linkId)->GetPhyBand(),
551 userInfo.GetAid12());
552 bufferTxTime = Max(bufferTxTime, duration);
553 }
554
555 if (bufferTxTime < maxDuration)
556 {
557 // the maximum buffer size can be transmitted within the allowed time
558 maxDuration = bufferTxTime;
559 }
560 else
561 {
562 // maxDuration may be a too short time. If it does not allow any station to
563 // transmit at least m_ulPsduSize bytes, give up the UL MU transmission for now
564 Time minDuration;
565 for (const auto& userInfo : m_trigger)
566 {
567 Time duration =
569 txVector,
570 m_apMac->GetWifiPhy(m_linkId)->GetPhyBand(),
571 userInfo.GetAid12());
572 minDuration = (minDuration.IsZero() ? duration : Min(minDuration, duration));
573 }
574
575 if (maxDuration < minDuration)
576 {
577 // maxDuration is a too short time, hence return NO_TX. In this way,
578 // no transmission will occur now and the next time we will try again
579 // performing an UL OFDMA transmission.
580 NS_LOG_DEBUG("Available time " << maxDuration.As(Time::MS) << " is too short");
581 return NO_TX;
582 }
583 }
584
585 // maxDuration is the time to grant to the stations. Finalize the Trigger Frame
586 uint16_t ulLength;
587 std::tie(ulLength, maxDuration) =
589 txVector,
590 m_apMac->GetWifiPhy(m_linkId)->GetPhyBand());
591 NS_LOG_DEBUG("TB PPDU duration: " << maxDuration.As(Time::MS));
592 m_trigger.SetUlLength(ulLength);
593 // set Preferred AC to the AC that gained channel access
594 for (auto& userInfo : m_trigger)
595 {
596 userInfo.SetBasicTriggerDepUserInfo(0, 0, m_edca->GetAccessCategory());
597 }
598
599 UpdateCredits(m_staListUl, maxDuration, txVector);
600
601 return UL_MU_TX;
602}
603
604void
606 CtrlTriggerHeader& trigger,
607 WifiTxParameters& txParams) const
608{
609 NS_LOG_FUNCTION(this << linkId << &txParams);
610
611 // remove unprotected EMLSR clients, unless this is a BSRP TF (which acts as ICF)
612 if (trigger.IsBsrp())
613 {
614 NS_LOG_INFO("BSRP TF is an ICF for unprotected EMLSR clients");
615 return;
616 }
617
618 NS_LOG_INFO("Checking unprotected EMLSR clients");
619 RemoveRecipientsFromTf(linkId, trigger, txParams, m_isUnprotectedEmlsrClient);
620}
621
622void
624 WifiPsduMap& psduMap,
625 WifiTxParameters& txParams) const
626{
627 NS_LOG_FUNCTION(this << linkId << &txParams);
628
629 NS_LOG_INFO("Checking unprotected EMLSR clients");
630 RemoveRecipientsFromDlMu(linkId, psduMap, txParams, m_isUnprotectedEmlsrClient);
631}
632
633Time
635{
636 auto phy = m_apMac->GetWifiPhy(linkId);
638 uint16_t aid{0};
639 Mac48Address staAddress;
640
641 // we assume that a Basic Trigger Frame is sent after a BSRP Trigger Frame. In order to
642 // compute the TX duration of the Multi-STA BlockAck, we need to find the bitmap length
643 // for each STA solicited by the Trigger Frame
644 for (const auto& userInfo : m_trigger)
645 {
646 aid = userInfo.GetAid12();
647 auto it = m_apMac->GetStaList(linkId).find(aid);
648 NS_ASSERT(it != m_apMac->GetStaList(linkId).cend());
649 staAddress = it->second;
650
651 // find a TID for which a BA agreement exists with the given originator
652 uint8_t tid = 0;
653 while (tid < 8 && !m_apMac->GetBaAgreementEstablishedAsRecipient(staAddress, tid))
654 {
655 ++tid;
656 }
657 NS_ASSERT_MSG(tid < 8, "No Block Ack agreement established with originator " << staAddress);
658
659 baType.m_bitmapLen.push_back(
660 m_apMac->GetBaTypeAsRecipient(staAddress, tid).m_bitmapLen.at(0));
661 }
662
663 NS_ASSERT_MSG(aid != 0, "No User Info field in the Trigger Frame");
664
665 auto multiStaBaTxVector =
666 GetWifiRemoteStationManager(linkId)->GetBlockAckTxVector(staAddress,
668
669 auto multiStaBaDuration = WifiPhy::CalculateTxDuration(GetBlockAckSize(baType),
670 multiStaBaTxVector,
671 phy->GetPhyBand());
672
673 return m_triggerTxDuration + m_defaultTbPpduDuration + multiStaBaDuration + 3 * phy->GetSifs();
674}
675
676void
678{
679 NS_LOG_FUNCTION(this << aid << address);
680
681 if (!m_apMac->GetHeSupported(address))
682 {
683 return;
684 }
685
686 auto mldOrLinkAddress = m_apMac->GetMldOrLinkAddressByAid(aid);
687 NS_ASSERT_MSG(mldOrLinkAddress, "AID " << aid << " not found");
688
689 for (auto& staList : m_staListDl)
690 {
691 // if this is not the first STA of a non-AP MLD to be notified, an entry
692 // for this non-AP MLD already exists
693 const auto staIt = std::find_if(staList.second.cbegin(),
694 staList.second.cend(),
695 [aid](auto&& info) { return info.aid == aid; });
696 if (staIt == staList.second.cend())
697 {
698 staList.second.push_back(MasterInfo{aid, *mldOrLinkAddress, 0.0});
699 }
700 }
701
702 const auto staIt = std::find_if(m_staListUl.cbegin(), m_staListUl.cend(), [aid](auto&& info) {
703 return info.aid == aid;
704 });
705 if (staIt == m_staListUl.cend())
706 {
707 m_staListUl.push_back(MasterInfo{aid, *mldOrLinkAddress, 0.0});
708 }
709}
710
711void
713{
714 NS_LOG_FUNCTION(this << aid << address);
715
716 if (!m_apMac->GetHeSupported(address))
717 {
718 return;
719 }
720
721 auto mldOrLinkAddress = m_apMac->GetMldOrLinkAddressByAid(aid);
722 NS_ASSERT_MSG(mldOrLinkAddress, "AID " << aid << " not found");
723
724 if (m_apMac->IsAssociated(*mldOrLinkAddress))
725 {
726 // Another STA of the non-AP MLD is still associated
727 return;
728 }
729
730 for (auto& staList : m_staListDl)
731 {
732 staList.second.remove_if([&aid](const MasterInfo& info) { return info.aid == aid; });
733 }
734 m_staListUl.remove_if([&aid](const MasterInfo& info) { return info.aid == aid; });
735}
736
739{
740 NS_LOG_FUNCTION(this);
741
742 AcIndex primaryAc = m_edca->GetAccessCategory();
743
744 if (m_staListDl[primaryAc].empty())
745 {
746 NS_LOG_DEBUG("No HE stations associated: return SU_TX");
747 return TxFormat::SU_TX;
748 }
749
750 std::size_t count =
751 std::min(static_cast<std::size_t>(m_nStations), m_staListDl[primaryAc].size());
752 std::size_t nCentral26TonesRus;
753 HeRu::RuType ruType =
754 HeRu::GetEqualSizedRusForStations(m_allowedWidth, count, nCentral26TonesRus);
755 NS_ASSERT(count >= 1);
756
758 {
759 nCentral26TonesRus = 0;
760 }
761
762 uint8_t currTid = wifiAcList.at(primaryAc).GetHighTid();
763
765
766 if (mpdu && mpdu->GetHeader().IsQosData())
767 {
768 currTid = mpdu->GetHeader().GetQosTid();
769 }
770
771 // determine the list of TIDs to check
772 std::vector<uint8_t> tids;
773
775 {
776 for (auto acIt = wifiAcList.find(primaryAc); acIt != wifiAcList.end(); acIt++)
777 {
778 uint8_t firstTid = (acIt->first == primaryAc ? currTid : acIt->second.GetHighTid());
779 tids.push_back(firstTid);
780 tids.push_back(acIt->second.GetOtherTid(firstTid));
781 }
782 }
783 else
784 {
785 tids.push_back(currTid);
786 }
787
788 Ptr<HeConfiguration> heConfiguration = m_apMac->GetHeConfiguration();
789 NS_ASSERT(heConfiguration);
790
794 m_txParams.m_txVector.SetGuardInterval(heConfiguration->GetGuardInterval());
795 m_txParams.m_txVector.SetBssColor(heConfiguration->m_bssColor);
796
797 // The TXOP limit can be exceeded by the TXOP holder if it does not transmit more
798 // than one Data or Management frame in the TXOP and the frame is not in an A-MPDU
799 // consisting of more than one MPDU (Sec. 10.22.2.8 of 802.11-2016).
800 // For the moment, we are considering just one MPDU per receiver.
801 Time actualAvailableTime = (m_initialFrame ? Time::Min() : m_availableTime);
802
803 // iterate over the associated stations until an enough number of stations is identified
804 auto staIt = m_staListDl[primaryAc].begin();
805 m_candidates.clear();
806
807 std::vector<uint8_t> ruAllocations;
809 ruAllocations.resize(numRuAllocs);
810 NS_ASSERT((m_candidates.size() % numRuAllocs) == 0);
811
812 while (staIt != m_staListDl[primaryAc].end() &&
813 m_candidates.size() <
814 std::min(static_cast<std::size_t>(m_nStations), count + nCentral26TonesRus))
815 {
816 NS_LOG_DEBUG("Next candidate STA (MAC=" << staIt->address << ", AID=" << staIt->aid << ")");
817
819 !m_apMac->GetEhtSupported(staIt->address))
820 {
821 NS_LOG_DEBUG("Skipping non-EHT STA because this DL MU PPDU is sent to EHT STAs only");
822 staIt++;
823 continue;
824 }
825
826 HeRu::RuType currRuType = (m_candidates.size() < count ? ruType : HeRu::RU_26_TONE);
827
828 // check if the AP has at least one frame to be sent to the current station
829 for (uint8_t tid : tids)
830 {
831 AcIndex ac = QosUtilsMapTidToAc(tid);
832 NS_ASSERT(ac >= primaryAc);
833 // check that a BA agreement is established with the receiver for the
834 // considered TID, since ack sequences for DL MU PPDUs require block ack
835 if (m_apMac->GetBaAgreementEstablishedAsOriginator(staIt->address, tid))
836 {
837 mpdu = m_apMac->GetQosTxop(ac)->PeekNextMpdu(m_linkId, tid, staIt->address);
838
839 // we only check if the first frame of the current TID meets the size
840 // and duration constraints. We do not explore the queues further.
841 if (mpdu)
842 {
843 mpdu = GetHeFem(m_linkId)->CreateAliasIfNeeded(mpdu);
844 // Use a temporary TX vector including only the STA-ID of the
845 // candidate station to check if the MPDU meets the size and time limits.
846 // An RU of the computed size is tentatively assigned to the candidate
847 // station, so that the TX duration can be correctly computed.
848 WifiTxVector suTxVector =
849 GetWifiRemoteStationManager(m_linkId)->GetDataTxVector(mpdu->GetHeader(),
851
852 WifiTxVector txVectorCopy = m_txParams.m_txVector;
853
854 // the first candidate STA determines the preamble type for the DL MU PPDU
855 if (m_candidates.empty() &&
857 {
859 m_txParams.m_txVector.SetEhtPpduType(0); // indicates DL OFDMA transmission
860 }
861
863 {{currRuType, 1, true},
864 suTxVector.GetMode().GetMcsValue(),
865 suTxVector.GetNss()});
866
867 if (!GetHeFem(m_linkId)->TryAddMpdu(mpdu, m_txParams, actualAvailableTime))
868 {
869 NS_LOG_DEBUG("Adding the peeked frame violates the time constraints");
870 m_txParams.m_txVector = txVectorCopy;
871 }
872 else
873 {
874 // the frame meets the constraints
875 NS_LOG_DEBUG("Adding candidate STA (MAC=" << staIt->address
876 << ", AID=" << staIt->aid
877 << ") TID=" << +tid);
878 m_candidates.emplace_back(staIt, mpdu);
879 break; // terminate the for loop
880 }
881 }
882 else
883 {
884 NS_LOG_DEBUG("No frames to send to " << staIt->address << " with TID=" << +tid);
885 }
886 }
887 }
888
889 // move to the next station in the list
890 staIt++;
891 }
892
893 if (m_candidates.empty())
894 {
895 if (m_forceDlOfdma)
896 {
897 NS_LOG_DEBUG("The AP does not have suitable frames to transmit: return NO_TX");
898 return NO_TX;
899 }
900 NS_LOG_DEBUG("The AP does not have suitable frames to transmit: return SU_TX");
901 return SU_TX;
902 }
903
904 return TxFormat::DL_MU_TX;
905}
906
907void
908RrMultiUserScheduler::FinalizeTxVector(WifiTxVector& txVector)
909{
910 // Do not log txVector because GetTxVectorForUlMu() left RUs undefined and
911 // printing them will crash the simulation
912 NS_LOG_FUNCTION(this);
913 NS_ASSERT(txVector.GetHeMuUserInfoMap().size() == m_candidates.size());
914
915 // compute how many stations can be granted an RU and the RU size
916 std::size_t nRusAssigned = m_candidates.size();
917 std::size_t nCentral26TonesRus;
918 HeRu::RuType ruType =
919 HeRu::GetEqualSizedRusForStations(m_allowedWidth, nRusAssigned, nCentral26TonesRus);
920
921 NS_LOG_DEBUG(nRusAssigned << " stations are being assigned a " << ruType << " RU");
922
923 if (!m_useCentral26TonesRus || m_candidates.size() == nRusAssigned)
924 {
925 nCentral26TonesRus = 0;
926 }
927 else
928 {
929 nCentral26TonesRus = std::min(m_candidates.size() - nRusAssigned, nCentral26TonesRus);
930 NS_LOG_DEBUG(nCentral26TonesRus << " stations are being assigned a 26-tones RU");
931 }
932
933 // re-allocate RUs based on the actual number of candidate stations
934 WifiTxVector::HeMuUserInfoMap heMuUserInfoMap;
935 std::swap(heMuUserInfoMap, txVector.GetHeMuUserInfoMap());
936
937 auto candidateIt = m_candidates.begin(); // iterator over the list of candidate receivers
938 auto ruSet = HeRu::GetRusOfType(m_allowedWidth, ruType);
939 auto ruSetIt = ruSet.begin();
940 auto central26TonesRus = HeRu::GetCentral26TonesRus(m_allowedWidth, ruType);
941 auto central26TonesRusIt = central26TonesRus.begin();
942
943 for (std::size_t i = 0; i < nRusAssigned + nCentral26TonesRus; i++)
944 {
945 NS_ASSERT(candidateIt != m_candidates.end());
946 auto mapIt = heMuUserInfoMap.find(candidateIt->first->aid);
947 NS_ASSERT(mapIt != heMuUserInfoMap.end());
948
949 txVector.SetHeMuUserInfo(mapIt->first,
950 {(i < nRusAssigned ? *ruSetIt++ : *central26TonesRusIt++),
951 mapIt->second.mcs,
952 mapIt->second.nss});
953 candidateIt++;
954 }
955
956 // remove candidates that will not be served
957 m_candidates.erase(candidateIt, m_candidates.end());
958}
959
960void
961RrMultiUserScheduler::UpdateCredits(std::list<MasterInfo>& staList,
962 Time txDuration,
963 const WifiTxVector& txVector)
964{
965 NS_LOG_FUNCTION(this << txDuration.As(Time::US) << txVector);
966
967 // find how many RUs have been allocated for each RU type
968 std::map<HeRu::RuType, std::size_t> ruMap;
969 for (const auto& userInfo : txVector.GetHeMuUserInfoMap())
970 {
971 ruMap.insert({userInfo.second.ru.GetRuType(), 0}).first->second++;
972 }
973
974 // The amount of credits received by each station equals the TX duration (in
975 // microseconds) divided by the number of stations.
976 double creditsPerSta = txDuration.ToDouble(Time::US) / staList.size();
977 // Transmitting stations have to pay a number of credits equal to the TX duration
978 // (in microseconds) times the allocated bandwidth share.
979 double debitsPerMhz =
980 txDuration.ToDouble(Time::US) /
981 std::accumulate(ruMap.begin(), ruMap.end(), 0, [](uint16_t sum, auto pair) {
982 return sum + pair.second * HeRu::GetBandwidth(pair.first);
983 });
984
985 // assign credits to all stations
986 for (auto& sta : staList)
987 {
988 sta.credits += creditsPerSta;
989 sta.credits = std::min(sta.credits, m_maxCredits.ToDouble(Time::US));
990 }
991
992 // subtract debits to the selected stations
993 for (auto& candidate : m_candidates)
994 {
995 auto mapIt = txVector.GetHeMuUserInfoMap().find(candidate.first->aid);
996 NS_ASSERT(mapIt != txVector.GetHeMuUserInfoMap().end());
997
998 candidate.first->credits -= debitsPerMhz * HeRu::GetBandwidth(mapIt->second.ru.GetRuType());
999 }
1000
1001 // sort the list in decreasing order of credits
1002 staList.sort([](const MasterInfo& a, const MasterInfo& b) { return a.credits > b.credits; });
1003}
1004
1006RrMultiUserScheduler::ComputeDlMuInfo()
1007{
1008 NS_LOG_FUNCTION(this);
1009
1010 if (m_candidates.empty())
1011 {
1012 return DlMuInfo();
1013 }
1014
1015 DlMuInfo dlMuInfo;
1016 std::swap(dlMuInfo.txParams.m_txVector, m_txParams.m_txVector);
1017 FinalizeTxVector(dlMuInfo.txParams.m_txVector);
1018
1019 m_txParams.Clear();
1020 Ptr<WifiMpdu> mpdu;
1021
1022 // Compute the TX params (again) by using the stored MPDUs and the final TXVECTOR
1023 Time actualAvailableTime = (m_initialFrame ? Time::Min() : m_availableTime);
1024
1025 for (const auto& candidate : m_candidates)
1026 {
1027 mpdu = candidate.second;
1028 NS_ASSERT(mpdu);
1029
1030 bool ret [[maybe_unused]] =
1031 GetHeFem(m_linkId)->TryAddMpdu(mpdu, dlMuInfo.txParams, actualAvailableTime);
1032 NS_ASSERT_MSG(ret,
1033 "Weird that an MPDU does not meet constraints when "
1034 "transmitted over a larger RU");
1035 }
1036
1037 // We have to complete the PSDUs to send
1038 Ptr<WifiMacQueue> queue;
1039
1040 for (const auto& candidate : m_candidates)
1041 {
1042 // Let us try first A-MSDU aggregation if possible
1043 mpdu = candidate.second;
1044 NS_ASSERT(mpdu);
1045 uint8_t tid = mpdu->GetHeader().GetQosTid();
1046 NS_ASSERT_MSG(mpdu->GetOriginal()->GetHeader().GetAddr1() == candidate.first->address,
1047 "RA of the stored MPDU must match the stored address");
1048
1049 NS_ASSERT(mpdu->IsQueued());
1050 Ptr<WifiMpdu> item = mpdu;
1051
1052 if (!mpdu->GetHeader().IsRetry())
1053 {
1054 // this MPDU must have been dequeued from the AC queue and we can try
1055 // A-MSDU aggregation
1056 item = GetHeFem(m_linkId)->GetMsduAggregator()->GetNextAmsdu(mpdu,
1057 dlMuInfo.txParams,
1058 m_availableTime);
1059
1060 if (!item)
1061 {
1062 // A-MSDU aggregation failed or disabled
1063 item = mpdu;
1064 }
1065 m_apMac->GetQosTxop(QosUtilsMapTidToAc(tid))->AssignSequenceNumber(item);
1066 }
1067
1068 // Now, let's try A-MPDU aggregation if possible
1069 std::vector<Ptr<WifiMpdu>> mpduList =
1070 GetHeFem(m_linkId)->GetMpduAggregator()->GetNextAmpdu(item,
1071 dlMuInfo.txParams,
1072 m_availableTime);
1073
1074 if (mpduList.size() > 1)
1075 {
1076 // A-MPDU aggregation succeeded, update psduMap
1077 dlMuInfo.psduMap[candidate.first->aid] = Create<WifiPsdu>(std::move(mpduList));
1078 }
1079 else
1080 {
1081 dlMuInfo.psduMap[candidate.first->aid] = Create<WifiPsdu>(item, true);
1082 }
1083 }
1084
1085 NS_ASSERT(dlMuInfo.txParams.m_txDuration.has_value());
1086 AcIndex primaryAc = m_edca->GetAccessCategory();
1087 UpdateCredits(m_staListDl[primaryAc],
1088 *dlMuInfo.txParams.m_txDuration,
1089 dlMuInfo.txParams.m_txVector);
1090
1091 NS_LOG_DEBUG("Next station to serve has AID=" << m_staListDl[primaryAc].front().aid);
1092
1093 return dlMuInfo;
1094}
1095
1097RrMultiUserScheduler::ComputeUlMuInfo()
1098{
1099 return UlMuInfo{m_trigger, m_triggerMacHdr, std::move(m_txParams)};
1100}
1101
1102} // namespace ns3
#define Max(a, b)
#define Min(a, b)
AttributeValue implementation for Boolean.
Definition boolean.h:26
Headers for Trigger frames.
std::size_t GetPaddingSize() const
WifiTxVector GetHeTbTxVector(uint16_t staId) const
Get the TX vector that the station with the given STA-ID will use to send the HE TB PPDU solicited by...
bool IsBsrp() const
Check if this is a Buffer Status Report Poll Trigger frame.
TriggerFrameType GetType() const
Get the Trigger Frame type.
ConstIterator begin() const
Get a const iterator pointing to the first User Info field in the list.
Time GetGuardInterval() const
Get the guard interval duration of the solicited HE TB PPDU.
void SetUlLength(uint16_t len)
Set the UL Length subfield of the Common Info field.
static std::pair< uint16_t, Time > ConvertHeTbPpduDurationToLSigLength(Time ppduDuration, const WifiTxVector &txVector, WifiPhyBand band)
Compute the L-SIG length value corresponding to the given HE TB PPDU duration.
Definition he-phy.cc:261
static RuType GetEqualSizedRusForStations(MHz_u bandwidth, std::size_t &nStations, std::size_t &nCentral26TonesRus)
Given the channel bandwidth and the number of stations candidate for being assigned an RU,...
Definition he-ru.cc:806
RuType
The different HE Resource Unit (RU) types.
Definition he-ru.h:32
@ RU_26_TONE
Definition he-ru.h:33
an EUI-48 address
MultiUserScheduler is an abstract base class defining the API that APs supporting at least VHT can us...
bool m_initialFrame
true if a TXOP is being started
void DoInitialize() override
Initialize() implementation.
Ptr< ApWifiMac > m_apMac
the AP wifi MAC
Time m_availableTime
the time available for frame exchange
void RemoveRecipientsFromTf(uint8_t linkId, CtrlTriggerHeader &trigger, WifiTxParameters &txParams, std::function< bool(uint8_t, Mac48Address)> predicate) const
Remove the User Info fields for which the given predicate is true from the given Trigger Frame.
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager(uint8_t linkId) const
Get the station manager attached to the AP on the given link.
uint8_t m_linkId
the ID of the link over which channel access has been granted
uint32_t GetMaxSizeOfQosNullAmpdu(const CtrlTriggerHeader &trigger) const
Get the maximum size in bytes among the A-MPDUs containing QoS Null frames and solicited by the given...
const std::function< bool(uint8_t, Mac48Address)> m_isUnprotectedEmlsrClient
predicate returning true if the device with the given (link) address is an EMLSR client that is not p...
Ptr< QosTxop > m_edca
the AC that gained channel access
Time m_defaultTbPpduDuration
the default duration of TB PPDUs solicited by Basic TFs
TxFormat GetLastTxFormat(uint8_t linkId) const
Get the format of the last transmission on the given link, as determined by the last call to NotifyAc...
void DoDispose() override
Destructor implementation.
Ptr< WifiMpdu > GetTriggerFrame(const CtrlTriggerHeader &trigger, uint8_t linkId) const
Get an MPDU containing the given Trigger Frame.
MHz_u m_allowedWidth
the allowed width for the current transmission
Ptr< HeFrameExchangeManager > GetHeFem(uint8_t linkId) const
Get the HE Frame Exchange Manager attached to the AP on the given link.
TxFormat
Enumeration of the possible transmission formats.
void RemoveRecipientsFromDlMu(uint8_t linkId, WifiPsduMap &psduMap, WifiTxParameters &txParams, std::function< bool(uint8_t, Mac48Address)> predicate) const
Remove PSDUs for which the given predicate is true from the given PSDU map.
Smart pointer class similar to boost::intrusive_ptr.
Ptr< WifiMpdu > PeekNextMpdu(uint8_t linkId, uint8_t tid=8, Mac48Address recipient=Mac48Address::GetBroadcast(), Ptr< const WifiMpdu > mpdu=nullptr)
Peek the next frame to transmit on the given link to the given receiver and of the given TID from the...
Definition qos-txop.cc:381
AcIndex GetAccessCategory() const
Get the access category of this object.
Definition qos-txop.cc:818
RrMultiUserScheduler is a simple OFDMA scheduler that indicates to perform a DL OFDMA transmission if...
TxFormat SelectTxFormat() override
Select the format of the next transmission.
bool m_enableBsrp
send a BSRP before an UL MU transmission
void NotifyStationAssociated(uint16_t aid, Mac48Address address)
Notify the scheduler that a station associated with the AP.
static TypeId GetTypeId()
Get the type ID.
uint32_t m_ulPsduSize
the size in byte of the solicited PSDU
std::list< CandidateInfo > m_candidates
Candidate stations for MU TX.
bool m_useCentral26TonesRus
whether to allocate central 26-tone RUs
bool m_forceDlOfdma
return DL_OFDMA even if no DL MU PPDU was built
bool m_enableUlOfdma
enable the scheduler to also return UL_OFDMA
void DoInitialize() override
Initialize() implementation.
void DoDispose() override
Destructor implementation.
void UpdateCredits(std::list< MasterInfo > &staList, Time txDuration, const WifiTxVector &txVector)
Update credits of the stations in the given list considering that a PPDU having the given duration is...
WifiMacHeader m_triggerMacHdr
MAC header for Trigger Frame.
uint8_t m_nStations
Number of stations/slots to fill.
Time m_triggerTxDuration
Trigger Frame TX duration.
void UpdateDlMuAfterProtection(uint8_t linkId, WifiPsduMap &psduMap, WifiTxParameters &txParams) const override
Update the given PSDU map after protection is completed on the given link.
WifiTxParameters m_txParams
TX parameters.
virtual TxFormat TrySendingDlMuPpdu()
Check if it is possible to send a DL MU PPDU given the current time limits.
void NotifyStationDeassociated(uint16_t aid, Mac48Address address)
Notify the scheduler that a station deassociated with the AP.
Time m_maxCredits
Max amount of credits a station can have.
void UpdateTriggerFrameAfterProtection(uint8_t linkId, CtrlTriggerHeader &trigger, WifiTxParameters &txParams) const override
Update the given Trigger Frame after protection is completed on the given link.
virtual WifiTxVector GetTxVectorForUlMu(std::function< bool(const MasterInfo &)> canBeSolicited)
Compute a TXVECTOR that can be used to construct a Trigger Frame to solicit transmissions from suitab...
Time GetExtraTimeForBsrpTfDurationId(uint8_t linkId) const override
When the TXOP limit is zero and the TXOP continues a SIFS after receiving a response to a BSRP TF,...
bool m_enableTxopSharing
allow A-MPDUs of different TIDs in a DL MU PPDU
CtrlTriggerHeader m_trigger
Trigger Frame to send.
std::map< AcIndex, std::list< MasterInfo > > m_staListDl
Per-AC list of stations (next to serve for DL first)
virtual bool CanSolicitStaInBasicTf(const MasterInfo &info) const
Determine whether the given STA can be solicited via a Basic Trigger Frame.
virtual TxFormat TrySendingBsrpTf()
Check if it is possible to send a BSRP Trigger Frame given the current time limits.
virtual bool CanSolicitStaInBsrpTf(const MasterInfo &info) const
Determine whether the given STA can be solicited via a BSRP Trigger Frame.
virtual TxFormat TrySendingBasicTf()
Check if it is possible to send a Basic Trigger Frame given the current time limits.
void FinalizeTxVector(WifiTxVector &txVector)
Finalize the given TXVECTOR by only including the largest subset of the current set of candidate stat...
std::list< MasterInfo > m_staListUl
List of stations to serve for UL.
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition time.cc:404
bool IsNegative() const
Exactly equivalent to t <= 0.
Definition nstime.h:313
static Time Min()
Minimum representable Time Not to be confused with Min(Time,Time).
Definition nstime.h:276
@ MS
millisecond
Definition nstime.h:106
double ToDouble(Unit unit) const
Get the Time value expressed in a particular unit.
Definition nstime.h:586
bool IsZero() const
Exactly equivalent to t == 0.
Definition nstime.h:304
AttributeValue implementation for Time.
Definition nstime.h:1431
a unique identifier for an interface.
Definition type-id.h:48
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
Hold an unsigned integer type.
Definition uinteger.h:34
Implements the IEEE 802.11 MAC header.
Mac48Address GetAddr1() const
Return the address in the Address 1 field.
void SetAddr1(Mac48Address address)
Fill the Address 1 field with the given address.
void SetAddr2(Mac48Address address)
Fill the Address 2 field with the given address.
uint8_t GetMcsValue() const
Definition wifi-mode.cc:152
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition wifi-phy.cc:1587
This class stores the TX parameters (TX vector, protection mechanism, acknowledgment mechanism,...
std::optional< Time > m_txDuration
TX duration of the frame.
std::unique_ptr< WifiProtection > m_protection
protection method
std::unique_ptr< WifiAcknowledgment > m_acknowledgment
acknowledgment method
WifiTxVector m_txVector
TXVECTOR of the frame being prepared.
void Clear()
Reset the TX parameters.
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
void SetEhtPpduType(uint8_t type)
Set the EHT_PPDU_TYPE parameter.
void SetGuardInterval(Time guardInterval)
Sets the guard interval duration (in nanoseconds)
std::map< uint16_t, HeMuUserInfo > HeMuUserInfoMap
map of HE MU specific user info parameters indexed by STA-ID
WifiMode GetMode(uint16_t staId=SU_STA_ID) const
If this TX vector is associated with an SU PPDU, return the selected payload transmission mode.
void SetHeMuUserInfo(uint16_t staId, HeMuUserInfo userInfo)
Set the HE MU user-specific transmission information for the given STA-ID.
WifiPreamble GetPreambleType() const
void SetChannelWidth(MHz_u channelWidth)
Sets the selected channelWidth.
const HeMuUserInfoMap & GetHeMuUserInfoMap() const
Get a const reference to the map HE MU user-specific transmission information indexed by STA-ID.
uint8_t GetNss(uint16_t staId=SU_STA_ID) const
If this TX vector is associated with an SU PPDU, return the number of spatial streams.
MHz_u GetChannelWidth() const
void SetBssColor(uint8_t color)
Set the BSS color.
void SetPreambleType(WifiPreamble preamble)
Sets the preamble type.
#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_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition assert.h:75
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
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition nstime.h:1432
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition nstime.h:1452
Ptr< const AttributeChecker > MakeUintegerChecker()
Definition uinteger.h:85
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition uinteger.h:35
#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_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#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_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:264
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1344
AcIndex QosUtilsMapTidToAc(uint8_t tid)
Maps TID (Traffic ID) to Access classes.
Definition qos-utils.cc:123
AcIndex
This enumeration defines the Access Categories as an enumeration with values corresponding to the AC ...
Definition qos-utils.h:62
@ WIFI_PREAMBLE_EHT_TB
@ WIFI_PREAMBLE_HE_TB
@ WIFI_PREAMBLE_EHT_MU
@ WIFI_PREAMBLE_HE_MU
@ AC_BE
Best Effort.
Definition qos-utils.h:64
Declaration of ns3::HePhy class and ns3::HeSigAParameters struct.
Definition first.py:1
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Time GetPpduMaxTime(WifiPreamble preamble)
Get the maximum PPDU duration (see Section 10.14 of 802.11-2016) for the PHY layers defining the aPPD...
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition callback.h:684
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:580
std::unordered_map< uint16_t, Ptr< WifiPsdu > > WifiPsduMap
Map of PSDUs indexed by STA-ID.
Definition wifi-mac.h:78
std::size_t Count20MHzSubchannels(MHz_u channelWidth)
Return the number of 20 MHz subchannels covering the channel width.
Definition wifi-utils.h:134
const std::map< AcIndex, WifiAc > wifiAcList
Map containing the four ACs in increasing order of priority (according to Table 10-1 "UP-to-AC Mappin...
Definition qos-utils.cc:115
@ WIFI_MAC_QOSDATA
uint32_t GetBlockAckSize(BlockAckType type)
Return the total BlockAck size (including FCS trailer).
Definition wifi-utils.cc:58
The different BlockAck variants.
std::vector< uint8_t > m_bitmapLen
Length (bytes) of included bitmaps.
Information to be provided in case of DL MU transmission.
WifiTxParameters txParams
the transmission parameters
WifiPsduMap psduMap
the DL MU PPDU to transmit
Information to be provided in case of UL MU transmission.
Information used to sort stations.
Mac48Address address
station's MAC Address
double credits
credits accumulated by the station
std::ofstream queueSize