14#include "ns3/eht-frame-exchange-manager.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"
35 TypeId(
"ns3::RrMultiUserScheduler")
39 .AddAttribute(
"NStations",
40 "The maximum number of stations that can be granted an RU in a DL MU "
45 .AddAttribute(
"EnableTxopSharing",
46 "If enabled, allow A-MPDUs of different TIDs in a DL MU PPDU.",
50 .AddAttribute(
"ForceDlOfdma",
51 "If enabled, return DL_MU_TX even if no DL MU PPDU could be built.",
55 .AddAttribute(
"EnableUlOfdma",
56 "If enabled, return UL_MU_TX if DL_MU_TX was returned the previous time.",
60 .AddAttribute(
"EnableBsrp",
61 "If enabled, send a BSRP Trigger Frame before an UL MU transmission.",
67 "The default size in bytes of the solicited PSDU (to be sent in a TB PPDU)",
71 .AddAttribute(
"UseCentral26TonesRus",
72 "If enabled, central 26-tone RUs are allocated, too, when the "
73 "selected RU type is at least 52 tones.",
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",
105 m_apMac->TraceConnectWithoutContext(
108 m_apMac->TraceConnectWithoutContext(
126 m_apMac->TraceDisconnectWithoutContext(
129 m_apMac->TraceDisconnectWithoutContext(
142 if (mpdu && !
m_apMac->GetHeSupported(mpdu->GetHeader().GetAddr1()))
177 auto heConfiguration =
m_apMac->GetHeConfiguration();
186 const auto firstCandidate =
196 (
m_apMac->GetEhtSupported() &&
m_apMac->GetEhtSupported(firstCandidate->address));
198 std::size_t nCentral26TonesRus;
207 nCentral26TonesRus = 0;
218 auto staIt = firstCandidate;
223 std::min<std::size_t>(
m_nStations, count + nCentral26TonesRus))
225 NS_LOG_DEBUG(
"Next candidate STA (MAC=" << staIt->address <<
", AID=" << staIt->aid <<
")");
228 !
m_apMac->GetEhtSupported(staIt->address))
231 "Skipping non-EHT STA because this Trigger Frame is only soliciting EHT STAs");
232 staIt = std::find_if(++staIt,
m_staListUl.end(), canBeSolicited);
240 ->GetAffiliatedStaAddress(staIt->address)
241 .value_or(staIt->address));
247 suTxVector.GetMode().GetMcsValue(),
248 suTxVector.GetNss()});
252 staIt = std::find_if(++staIt,
m_staListUl.end(), canBeSolicited);
272 <<
": skipping station");
281 if (
m_apMac->GetBaAgreementEstablishedAsRecipient(info.
address, tid))
290 <<
": skipping station");
304 for (uint8_t tid = 0; tid < 8; ++tid)
316 <<
": skipping station");
323 {WIFI_QOSDATA_QUEUE, WIFI_UNICAST, *mldAddr, 0},
327 {WIFI_QOSDATA_QUEUE, WIFI_UNICAST, *mldAddr, 0},
331 NS_LOG_INFO(
"EMLSR client " << *mldAddr <<
" is using another link: skipping station");
345 NS_LOG_DEBUG(
"No HE stations associated: return SU_TX");
352 if (txVector.GetHeMuUserInfoMap().empty())
390 NS_LOG_DEBUG(
"Remaining TXOP duration is not enough for BSRP TF exchange");
395 Time qosNullTxDuration;
401 userInfo.GetAid12());
402 qosNullTxDuration =
Max(qosNullTxDuration, duration);
420 NS_LOG_DEBUG(
"Remaining TXOP duration is not enough for BSRP TF exchange");
456 NS_LOG_DEBUG(
"No HE stations associated: return SU_TX");
466 if (txVector.GetHeMuUserInfoMap().empty())
474 for (
const auto& candidate : txVector.GetHeMuUserInfoMap())
476 auto address =
m_apMac->GetMldOrLinkAddressByAid(candidate.first);
477 NS_ASSERT_MSG(address,
"AID " << candidate.first <<
" not found");
482 NS_LOG_DEBUG(
"Buffer status of station " << *address <<
" is unknown");
487 NS_LOG_DEBUG(
"Buffer status of station " << *address <<
" is not limited");
488 maxBufferSize = 0xffffffff;
497 if (maxBufferSize == 0)
523 NS_LOG_DEBUG(
"Remaining TXOP duration is not enough for UL MU exchange");
537 maxDuration =
Min(maxDuration,
543 NS_LOG_DEBUG(
"Remaining TXOP duration is not enough for UL MU exchange");
555 userInfo.GetAid12());
556 bufferTxTime =
Max(bufferTxTime, duration);
559 if (bufferTxTime < maxDuration)
562 maxDuration = bufferTxTime;
575 userInfo.GetAid12());
576 minDuration = (minDuration.
IsZero() ? duration :
Min(minDuration, duration));
579 if (maxDuration < minDuration)
591 std::tie(ulLength, maxDuration) =
618 NS_LOG_INFO(
"BSRP TF is an ICF for unprotected EMLSR clients");
640 auto phy =
m_apMac->GetWifiPhy(linkId);
650 aid = userInfo.GetAid12();
651 auto it =
m_apMac->GetStaList(linkId).find(aid);
653 staAddress = it->second;
657 while (tid < 8 && !m_apMac->GetBaAgreementEstablishedAsRecipient(staAddress, tid))
661 NS_ASSERT_MSG(tid < 8,
"No Block Ack agreement established with originator " << staAddress);
664 m_apMac->GetBaTypeAsRecipient(staAddress, tid).m_bitmapLen.at(0));
667 NS_ASSERT_MSG(aid != 0,
"No User Info field in the Trigger Frame");
669 auto multiStaBaTxVector =
685 if (!
m_apMac->GetHeSupported(address))
690 auto mldOrLinkAddress =
m_apMac->GetMldOrLinkAddressByAid(aid);
691 NS_ASSERT_MSG(mldOrLinkAddress,
"AID " << aid <<
" not found");
697 const auto staIt = std::find_if(staList.second.cbegin(),
698 staList.second.cend(),
699 [aid](
auto&& info) { return info.aid == aid; });
700 if (staIt == staList.second.cend())
702 staList.second.push_back(
MasterInfo{aid, *mldOrLinkAddress, 0.0});
707 return info.aid == aid;
720 if (!
m_apMac->GetHeSupported(address))
725 auto mldOrLinkAddress =
m_apMac->GetMldOrLinkAddressByAid(aid);
726 NS_ASSERT_MSG(mldOrLinkAddress,
"AID " << aid <<
" not found");
728 if (
m_apMac->IsAssociated(*mldOrLinkAddress))
736 staList.second.remove_if([&aid](
const MasterInfo& info) {
return info.
aid == aid; });
750 NS_LOG_DEBUG(
"No HE stations associated: return SU_TX");
756 std::size_t nCentral26TonesRus{0};
758 uint8_t currTid =
wifiAcList.at(primaryAc).GetHighTid();
762 if (mpdu && mpdu->GetHeader().IsQosData())
764 currTid = mpdu->GetHeader().GetQosTid();
768 std::vector<uint8_t> tids;
774 uint8_t firstTid = (acIt->first == primaryAc ? currTid : acIt->second.GetHighTid());
775 tids.push_back(firstTid);
776 tids.push_back(acIt->second.GetOtherTid(firstTid));
781 tids.push_back(currTid);
803 std::vector<uint8_t> ruAllocations;
805 ruAllocations.resize(numRuAllocs);
811 std::min(
static_cast<std::size_t
>(
m_nStations), count + nCentral26TonesRus))
813 NS_LOG_DEBUG(
"Next candidate STA (MAC=" << staIt->address <<
", AID=" << staIt->aid <<
")");
816 !
m_apMac->GetEhtSupported(staIt->address))
818 NS_LOG_DEBUG(
"Skipping non-EHT STA because this DL MU PPDU is sent to EHT STAs only");
824 for (uint8_t tid : tids)
830 if (
m_apMac->GetBaAgreementEstablishedAsOriginator(staIt->address, tid))
832 mpdu =
m_apMac->GetQosTxop(ac)->PeekNextMpdu(
m_linkId, tid, staIt->address);
867 nCentral26TonesRus = 0;
872 const auto currRuType =
880 {ru, suTxVector.GetMode().GetMcsValue(), suTxVector.GetNss()});
884 NS_LOG_DEBUG(
"Adding the peeked frame violates the time constraints");
890 NS_LOG_DEBUG(
"Adding candidate STA (MAC=" << staIt->address
891 <<
", AID=" << staIt->aid
892 <<
") TID=" << +tid);
899 NS_LOG_DEBUG(
"No frames to send to " << staIt->address <<
" with TID=" << +tid);
912 NS_LOG_DEBUG(
"The AP does not have suitable frames to transmit: return NO_TX");
915 NS_LOG_DEBUG(
"The AP does not have suitable frames to transmit: return SU_TX");
932 std::size_t nCentral26TonesRus;
938 NS_LOG_DEBUG(nRusAssigned <<
" stations are being assigned a " << ruType <<
" RU");
942 nCentral26TonesRus = 0;
946 nCentral26TonesRus = std::min(
m_candidates.size() - nRusAssigned, nCentral26TonesRus);
947 NS_LOG_DEBUG(nCentral26TonesRus <<
" stations are being assigned a 26-tones RU");
957 auto ruSetIt = ruSet.begin();
959 auto central26TonesRusIt = central26TonesRus.begin();
961 for (std::size_t i = 0; i < nRusAssigned + nCentral26TonesRus; i++)
964 auto mapIt = heMuUserInfoMap.find(candidateIt->first->aid);
965 NS_ASSERT(mapIt != heMuUserInfoMap.end());
968 {(i < nRusAssigned ? *ruSetIt++ : *central26TonesRusIt++),
986 std::map<RuType, std::size_t> ruMap;
997 double debitsPerMhz =
999 std::accumulate(ruMap.begin(), ruMap.end(), 0, [](uint16_t sum,
auto pair) {
1000 return sum + pair.second * WifiRu::GetBandwidth(pair.first);
1004 for (
auto& sta : staList)
1006 sta.credits += creditsPerSta;
1016 candidate.first->credits -=
1046 mpdu = candidate.second;
1049 bool ret [[maybe_unused]] =
1052 "Weird that an MPDU does not meet constraints when "
1053 "transmitted over a larger RU");
1062 mpdu = candidate.second;
1064 uint8_t tid = mpdu->GetHeader().GetQosTid();
1065 NS_ASSERT_MSG(mpdu->GetOriginal()->GetHeader().GetAddr1() == candidate.first->address,
1066 "RA of the stored MPDU must match the stored address");
1071 if (!mpdu->GetHeader().IsRetry())
1088 std::vector<Ptr<WifiMpdu>> mpduList =
1093 if (mpduList.size() > 1)
AttributeValue implementation for Boolean.
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.
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...
AcIndex GetAccessCategory() const
Get the access category of this object.
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.
~RrMultiUserScheduler() override
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.
UlMuInfo ComputeUlMuInfo() override
Prepare the information required to solicit an UL MU transmission.
DlMuInfo ComputeDlMuInfo() override
Compute the information required to perform a DL MU transmission.
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.
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
bool IsNegative() const
Exactly equivalent to t <= 0.
static Time Min()
Minimum representable Time Not to be confused with Min(Time,Time).
double ToDouble(Unit unit) const
Get the Time value expressed in a particular unit.
bool IsZero() const
Exactly equivalent to t == 0.
AttributeValue implementation for Time.
a unique identifier for an interface.
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Hold an unsigned integer type.
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
std::variant< HeRu::RuSpec, EhtRu::RuSpec > RuSpec
variant of the RU specification
static std::vector< RuSpec > GetRusOfType(MHz_u bw, RuType ruType, WifiModulationClass mc)
Get the set of distinct RUs of the given type (number of tones) available in an MU PPDU of the given ...
static MHz_u GetBandwidth(RuType ruType)
Get the approximate bandwidth occupied by a RU.
static RuType GetEqualSizedRusForStations(MHz_u bandwidth, std::size_t &nStations, std::size_t &nCentral26TonesRus, WifiModulationClass mc)
Given the channel bandwidth and the number of stations candidate for being assigned an RU,...
static RuType GetRuType(RuSpec ru)
Get the type of a given RU.
static std::vector< RuSpec > GetCentral26TonesRus(MHz_u bw, RuType ruType, WifiModulationClass mc)
Get the set of 26-tone RUs that can be additionally allocated if the given bandwidth is split in RUs ...
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
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.
WifiModulationClass GetModulationClass() const
Get the modulation class specified by this TXVECTOR.
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,...
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Ptr< const AttributeChecker > MakeBooleanChecker()
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Ptr< const AttributeChecker > MakeUintegerChecker()
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
#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.
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Time Seconds(double value)
Construct a Time in the indicated unit.
AcIndex QosUtilsMapTidToAc(uint8_t tid)
Maps TID (Traffic ID) to Access classes.
WifiModulationClass
This enumeration defines the modulation classes per (Table 10-6 "Modulation classes"; IEEE 802....
AcIndex
This enumeration defines the Access Categories as an enumeration with values corresponding to the AC ...
@ WIFI_MOD_CLASS_EHT
EHT (Clause 36)
@ WIFI_MOD_CLASS_HE
HE (Clause 27)
@ WAITING_EMLSR_TRANSITION_DELAY
Declaration of ns3::HePhy class and ns3::HeSigAParameters struct.
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...
bool IsEht(WifiPreamble preamble)
Return true if a preamble corresponds to an EHT transmission.
RuType
The different Resource Unit (RU) types.
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
std::unordered_map< uint16_t, Ptr< WifiPsdu > > WifiPsduMap
Map of PSDUs indexed by STA-ID.
std::size_t Count20MHzSubchannels(MHz_u channelWidth)
Return the number of 20 MHz subchannels covering the channel width.
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...
uint32_t GetBlockAckSize(BlockAckType type)
Return the total BlockAck size (including FCS trailer).
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
uint16_t aid
station's AID