wifi: Add Special User Info field for trigger frames soliciting EHT TB PPDUs

This commit is contained in:
Sébastien Deronne
2024-11-17 11:11:02 +01:00
parent 45a48eb3b9
commit b953cae778
4 changed files with 323 additions and 3 deletions

View File

@@ -97,6 +97,7 @@ The minimum clang-format version is version 15.
- (wifi) 2009! - Added WifiTxStatsHelper for Wi-Fi MAC-level tracing.
- (wifi) - Added support for 802.11aa groupcast with retries (GCR). Both unsolicited retries (GCR-UR) and Block Ack (GCR-BA) mechanisms are implemented.
- (zigbee) Added a new Zigbee module.
- (wifi) Trigger frames have been extended to support Special User Info field
### Bugs fixed

View File

@@ -195,7 +195,7 @@ cpp_examples = [
"True",
),
(
"wifi-eht-network --simulationTime=0.25s --udp=0 --downlink=0 --useRts=0 --nStations=4 --dlAckType=AGGR-MU-BAR --enableUlOfdma=1 --enableBsrp=1 --mpduBufferSize=1024 --mcs=8 --muSchedAccessReqInterval=45ms --frequency2=6 --minExpectedThroughput=50 --maxExpectedThroughput=550",
"wifi-eht-network --simulationTime=0.25s --udp=0 --downlink=0 --useRts=0 --nStations=4 --dlAckType=AGGR-MU-BAR --enableUlOfdma=1 --enableBsrp=1 --mpduBufferSize=1024 --mcs=8 --muSchedAccessReqInterval=45ms --frequency2=6 --minExpectedThroughput=50 --maxExpectedThroughput=550 --RngRun=3",
"True",
"True",
),

View File

@@ -1391,6 +1391,9 @@ CtrlTriggerUserInfoField::GetPreambleType() const
void
CtrlTriggerUserInfoField::SetAid12(uint16_t aid)
{
NS_ASSERT_MSG((m_variant == TriggerFrameVariant::HE) || (aid != AID_SPECIAL_USER),
std::to_string(AID_SPECIAL_USER)
<< " is reserved for Special User Info Field in EHT variant");
m_aid12 = aid & 0x0fff;
}
@@ -1730,6 +1733,176 @@ CtrlTriggerUserInfoField::GetMuBarTriggerDepUserInfo() const
return m_muBarTriggerDependentUserInfo;
}
/*****************************************
* Trigger frame - Special User Info field
*****************************************/
CtrlTriggerSpecialUserInfoField::CtrlTriggerSpecialUserInfoField(TriggerFrameType triggerType)
: m_triggerType(triggerType)
{
}
CtrlTriggerSpecialUserInfoField&
CtrlTriggerSpecialUserInfoField::operator=(const CtrlTriggerSpecialUserInfoField& other)
{
// check for self-assignment
if (&other == this)
{
return *this;
}
m_triggerType = other.m_triggerType;
m_ulBwExt = other.m_ulBwExt;
m_muBarTriggerDependentUserInfo = other.m_muBarTriggerDependentUserInfo;
return *this;
}
uint32_t
CtrlTriggerSpecialUserInfoField::GetSerializedSize() const
{
uint32_t size = 0;
size += 5; // User Info (excluding Trigger Dependent User Info)
switch (m_triggerType)
{
case TriggerFrameType::BASIC_TRIGGER:
case TriggerFrameType::BFRP_TRIGGER:
size += 1;
break;
case TriggerFrameType::MU_BAR_TRIGGER:
size +=
m_muBarTriggerDependentUserInfo.GetSerializedSize(); // BAR Control and BAR Information
break;
default:;
// The Trigger Dependent User Info subfield is not present in the other variants
}
return size;
}
Buffer::Iterator
CtrlTriggerSpecialUserInfoField::Serialize(Buffer::Iterator start) const
{
NS_ABORT_MSG_IF(m_triggerType == TriggerFrameType::BFRP_TRIGGER,
"BFRP Trigger frame is not supported");
NS_ABORT_MSG_IF(m_triggerType == TriggerFrameType::GCR_MU_BAR_TRIGGER,
"GCR-MU-BAR Trigger frame is not supported");
NS_ABORT_MSG_IF(m_triggerType == TriggerFrameType::NFRP_TRIGGER,
"NFRP Trigger frame is not supported");
Buffer::Iterator i = start;
uint32_t userInfo = 0;
userInfo |= (AID_SPECIAL_USER & 0x0fff);
userInfo |= (static_cast<uint32_t>(m_ulBwExt) << 15);
i.WriteHtolsbU32(userInfo);
i.WriteU8(0);
// TODO: EHT Spatial Reuse and U-SIG Disregard And Validate
if (m_triggerType == TriggerFrameType::BASIC_TRIGGER)
{
// The length is one octet and all the subfields are reserved in a Basic Trigger frame and
// in a BFRP Trigger frame
i.WriteU8(0);
}
else if (m_triggerType == TriggerFrameType::MU_BAR_TRIGGER)
{
m_muBarTriggerDependentUserInfo.Serialize(i);
i.Next(m_muBarTriggerDependentUserInfo.GetSerializedSize());
}
return i;
}
Buffer::Iterator
CtrlTriggerSpecialUserInfoField::Deserialize(Buffer::Iterator start)
{
NS_ABORT_MSG_IF(m_triggerType == TriggerFrameType::BFRP_TRIGGER,
"BFRP Trigger frame is not supported");
NS_ABORT_MSG_IF(m_triggerType == TriggerFrameType::GCR_MU_BAR_TRIGGER,
"GCR-MU-BAR Trigger frame is not supported");
NS_ABORT_MSG_IF(m_triggerType == TriggerFrameType::NFRP_TRIGGER,
"NFRP Trigger frame is not supported");
Buffer::Iterator i = start;
const auto userInfo = i.ReadLsbtohU32();
i.ReadU8();
// TODO: EHT Spatial Reuse and U-SIG Disregard And Validate
const uint16_t aid12 = userInfo & 0x0fff;
NS_ABORT_MSG_IF(aid12 != AID_SPECIAL_USER, "Failed to deserialize Special User Info field");
m_ulBwExt = (userInfo >> 15) & 0x03;
if (m_triggerType == TriggerFrameType::BASIC_TRIGGER)
{
i.ReadU8();
}
else if (m_triggerType == TriggerFrameType::MU_BAR_TRIGGER)
{
const auto len = m_muBarTriggerDependentUserInfo.Deserialize(i);
i.Next(len);
}
return i;
}
TriggerFrameType
CtrlTriggerSpecialUserInfoField::GetType() const
{
return m_triggerType;
}
void
CtrlTriggerSpecialUserInfoField::SetUlBwExt(MHz_u bw)
{
switch (static_cast<uint16_t>(bw))
{
case 20:
case 40:
case 80:
m_ulBwExt = 0;
break;
case 160:
m_ulBwExt = 1;
break;
case 320:
m_ulBwExt = 2;
// TODO: differentiate channelization 1 from channelization 2
break;
default:
NS_FATAL_ERROR("Bandwidth value not allowed.");
break;
}
}
uint8_t
CtrlTriggerSpecialUserInfoField::GetUlBwExt() const
{
return m_ulBwExt;
}
void
CtrlTriggerSpecialUserInfoField::SetMuBarTriggerDepUserInfo(const CtrlBAckRequestHeader& bar)
{
NS_ABORT_MSG_IF(m_triggerType != TriggerFrameType::MU_BAR_TRIGGER,
"Not a MU-BAR Trigger frame");
NS_ABORT_MSG_IF(bar.GetType().m_variant != BlockAckReqType::COMPRESSED &&
bar.GetType().m_variant != BlockAckReqType::MULTI_TID,
"BAR Control indicates it is neither the Compressed nor the Multi-TID variant");
m_muBarTriggerDependentUserInfo = bar;
}
const CtrlBAckRequestHeader&
CtrlTriggerSpecialUserInfoField::GetMuBarTriggerDepUserInfo() const
{
NS_ABORT_MSG_IF(m_triggerType != TriggerFrameType::MU_BAR_TRIGGER,
"Not a MU-BAR Trigger frame");
return m_muBarTriggerDependentUserInfo;
}
/***********************************
* Trigger frame
***********************************/
@@ -1753,6 +1926,7 @@ CtrlTriggerHeader::CtrlTriggerHeader()
CtrlTriggerHeader::CtrlTriggerHeader(TriggerFrameType type, const WifiTxVector& txVector)
: CtrlTriggerHeader()
{
m_triggerType = type;
NS_ABORT_MSG_IF(m_triggerType == TriggerFrameType::MU_RTS_TRIGGER,
"This constructor cannot be used for MU-RTS");
@@ -1769,7 +1943,13 @@ CtrlTriggerHeader::CtrlTriggerHeader(TriggerFrameType type, const WifiTxVector&
<< txVector.GetPreambleType());
}
m_triggerType = type;
// special user is always present if solicited TB PPDU format is EHT or later
if (txVector.GetModulationClass() >= WifiModulationClass::WIFI_MOD_CLASS_EHT)
{
NS_ASSERT(m_variant == TriggerFrameVariant::EHT);
m_specialUserInfoField.emplace(m_triggerType);
}
SetUlBandwidth(txVector.GetChannelWidth());
SetUlLength(txVector.GetLength());
const auto gi = txVector.GetGuardInterval().GetNanoSeconds();
@@ -1781,6 +1961,7 @@ CtrlTriggerHeader::CtrlTriggerHeader(TriggerFrameType type, const WifiTxVector&
{
m_giAndLtfType = 2;
}
for (auto& userInfo : txVector.GetHeMuUserInfoMap())
{
CtrlTriggerUserInfoField& ui = AddUserInfoField();
@@ -1814,6 +1995,8 @@ CtrlTriggerHeader::operator=(const CtrlTriggerHeader& trigger)
m_apTxPower = trigger.m_apTxPower;
m_ulSpatialReuse = trigger.m_ulSpatialReuse;
m_padding = trigger.m_padding;
m_specialUserInfoField.reset();
m_specialUserInfoField = trigger.m_specialUserInfoField;
m_userInfoFields.clear();
m_userInfoFields = trigger.m_userInfoFields;
return *this;
@@ -1853,6 +2036,11 @@ CtrlTriggerHeader::SetVariant(TriggerFrameVariant variant)
NS_ABORT_MSG_IF(!m_userInfoFields.empty(),
"Cannot change Common Info field variant if User Info fields are present");
m_variant = variant;
// special user is always present if User Info field variant is EHT or later
if (!m_specialUserInfoField && (m_variant >= TriggerFrameVariant::EHT))
{
m_specialUserInfoField.emplace(m_triggerType);
}
}
TriggerFrameVariant
@@ -1873,6 +2061,12 @@ CtrlTriggerHeader::GetSerializedSize() const
size += 4;
}
if (m_specialUserInfoField)
{
NS_ASSERT(m_variant == TriggerFrameVariant::EHT);
size += m_specialUserInfoField->GetSerializedSize();
}
for (auto& ui : m_userInfoFields)
{
size += ui.GetSerializedSize();
@@ -1912,6 +2106,12 @@ CtrlTriggerHeader::Serialize(Buffer::Iterator start) const
i.WriteHtolsbU64(commonInfo);
if (m_specialUserInfoField)
{
NS_ASSERT(m_variant == TriggerFrameVariant::EHT);
i = m_specialUserInfoField->Serialize(i);
}
for (auto& ui : m_userInfoFields)
{
i = ui.Serialize(i);
@@ -1950,6 +2150,18 @@ CtrlTriggerHeader::Deserialize(Buffer::Iterator start)
NS_ABORT_MSG_IF(m_triggerType == TriggerFrameType::NFRP_TRIGGER,
"NFRP Trigger frame is not supported");
if (m_variant == TriggerFrameVariant::EHT)
{
m_specialUserInfoField.reset();
const auto userInfo = i.ReadLsbtohU16();
i.Prev(2);
if (const auto aid12 = userInfo & 0x0fff; aid12 == AID_SPECIAL_USER)
{
m_specialUserInfoField.emplace(m_triggerType);
i = m_specialUserInfoField->Deserialize(i);
}
}
while (i.GetRemainingSize() >= 2)
{
// read the first 2 bytes to check if we encountered the Padding field
@@ -2246,8 +2458,10 @@ CtrlTriggerHeader::GetPaddingSize() const
CtrlTriggerHeader
CtrlTriggerHeader::GetCommonInfoField() const
{
// make a copy of this Trigger Frame and remove the User Info fields from the copy
// make a copy of this Trigger Frame and remove the User Info fields (including the Special User
// Info field) from the copy
CtrlTriggerHeader trigger(*this);
trigger.m_specialUserInfoField.reset();
trigger.m_userInfoFields.clear();
return trigger;
}

View File

@@ -17,6 +17,7 @@
#include "ns3/mac48-address.h"
#include <list>
#include <optional>
#include <vector>
namespace ns3
@@ -910,6 +911,107 @@ class CtrlTriggerUserInfoField
m_muBarTriggerDependentUserInfo; //!< MU-BAR variant of Trigger Dependent User Info subfield
};
/**
* @ingroup wifi
* @brief Special User Info field of Trigger frames.
*
* Trigger frames have been extended by 802.11be amendment and may include one Special User Info
* field for a solicited EHT TB PPDU (see Section 9.3.1.22.3 of D7.0). The Special User Info field
* is located immediately after the Common Info field, it does not carry user specific information
* but carries extended common information not provided in the Common Info field.
*/
class CtrlTriggerSpecialUserInfoField
{
public:
/**
* Constructor
*
* @param triggerType the Trigger frame type
*/
explicit CtrlTriggerSpecialUserInfoField(TriggerFrameType triggerType);
/**
* Copy assignment operator.
*
* @param other the Special User Info field to copy
* @return a reference to the copied object
*
* Checks that the given Special User Info fields is included in the same type of Trigger Frame.
*/
CtrlTriggerSpecialUserInfoField& operator=(const CtrlTriggerSpecialUserInfoField& other);
/**
* Get the expected size of this Special User Info field
*
* @return the expected size of this Special User Info field.
*/
uint32_t GetSerializedSize() const;
/**
* Serialize the Special User Info field to the given buffer.
*
* @param start an iterator which points to where the header should
* be written
* @return Buffer::Iterator to the next available buffer
*/
Buffer::Iterator Serialize(Buffer::Iterator start) const;
/**
* Deserialize the Special User Info field from the given buffer.
*
* @param start an iterator which points to where the header should
* read from
* @return Buffer::Iterator to the next available buffer
*/
Buffer::Iterator Deserialize(Buffer::Iterator start);
/**
* Get the type of the Trigger Frame this Special User Info field belongs to.
*
* @return the type of the Trigger Frame this Special User Info field belongs to
*/
TriggerFrameType GetType() const;
/**
* Set the UL Bandwidth Extension subfield value of the solicited EHT TB PPDU.
*
* @param bw bandwidth (allowed values: 20 MHz, 40 MHz, 80 MHz, 160 MHz, 320 MHz)
*/
void SetUlBwExt(MHz_u bw);
/**
* Get the UL Bandwidth Extension subfield value of the solicited EHT TB PPDU.
*
* @return the UL Bandwidth Extension subfield value
*/
uint8_t GetUlBwExt() const;
/**
* Set the Trigger Dependent Special User Info subfield for the MU-BAR variant of Trigger
* frames, which includes the BAR Type subfield. The BAR Type subfield must indicate a
* Compressed BAR in an MU BAR Trigger frame.
*
* @param bar the BlockAckRequest header object including the BAR Control
* subfield and the BAR Information subfield
*/
void SetMuBarTriggerDepUserInfo(const CtrlBAckRequestHeader& bar);
/**
* Get the Trigger Dependent Special User Info subfield for the MU-BAR variant of
* Trigger frames, which includes a BAR Type subfield.
*
* @return the BlockAckRequest header object including the BAR Control
* subfield and the BAR Information subfield
*/
const CtrlBAckRequestHeader& GetMuBarTriggerDepUserInfo() const;
private:
TriggerFrameType m_triggerType{}; //!< Trigger type
uint8_t m_ulBwExt{}; //!< UL Bandwidth Extension
CtrlBAckRequestHeader m_muBarTriggerDependentUserInfo{}; //!< MU-BAR variant of Trigger
//!< Dependent User Info subfield
};
/**
* @ingroup wifi
* @brief Headers for Trigger frames.
@@ -1339,6 +1441,9 @@ class CtrlTriggerHeader : public Header
uint16_t m_ulSpatialReuse; //!< Value for the Spatial Reuse field in HE-SIG-A
std::size_t m_padding; //!< the size in bytes of the Padding field
std::optional<CtrlTriggerSpecialUserInfoField>
m_specialUserInfoField; //!< Special User Info field (EHT variant only)
/**
* List of User Info fields
*/