network: Add support for EHT field in radiotap header
This commit is contained in:
@@ -269,6 +269,15 @@ RadiotapHeader::Serialize(Buffer::Iterator start) const
|
||||
{
|
||||
SerializeUsig(start);
|
||||
}
|
||||
|
||||
//
|
||||
// EHT field.
|
||||
// Reference: https://www.radiotap.org/fields/EHT.html
|
||||
//
|
||||
if (m_presentExt && (*m_presentExt & RADIOTAP_EHT_SIG)) // bit 34
|
||||
{
|
||||
SerializeEht(start);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
@@ -282,7 +291,6 @@ RadiotapHeader::Deserialize(Buffer::Iterator start)
|
||||
|
||||
m_length = start.ReadU16(); // entire length of radiotap data + header
|
||||
m_present = start.ReadU32(); // bits describing which fields follow header
|
||||
|
||||
uint32_t bytesRead = 8;
|
||||
|
||||
if (m_present & RADIOTAP_EXT)
|
||||
@@ -520,6 +528,15 @@ RadiotapHeader::Deserialize(Buffer::Iterator start)
|
||||
bytesRead += DeserializeUsig(start, bytesRead);
|
||||
}
|
||||
|
||||
//
|
||||
// EHT field.
|
||||
// Reference: https://www.radiotap.org/fields/EHT.html
|
||||
//
|
||||
if (m_presentExt && (*m_presentExt & RADIOTAP_EHT_SIG)) // bit 34
|
||||
{
|
||||
bytesRead += DeserializeEht(start, bytesRead);
|
||||
}
|
||||
|
||||
NS_ASSERT_MSG(m_length == bytesRead,
|
||||
"RadiotapHeader::Deserialize(): expected and actual lengths inconsistent");
|
||||
return bytesRead;
|
||||
@@ -563,6 +580,10 @@ RadiotapHeader::Print(std::ostream& os) const
|
||||
{
|
||||
PrintUsig(os);
|
||||
}
|
||||
if (m_presentExt && (*m_presentExt & RADIOTAP_EHT_SIG))
|
||||
{
|
||||
PrintEht(os);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1070,4 +1091,100 @@ RadiotapHeader::PrintUsig(std::ostream& os) const
|
||||
<< m_usigFields.value << " usig.mask=0x" << m_usigFields.mask << std::dec;
|
||||
}
|
||||
|
||||
void
|
||||
RadiotapHeader::SetEhtFields(const EhtFields& ehtFields)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << ehtFields.known);
|
||||
if (!m_presentExt)
|
||||
{
|
||||
m_present |= RADIOTAP_TLV | RADIOTAP_EXT;
|
||||
m_presentExt = 0;
|
||||
m_length += sizeof(RadiotapExtFlags);
|
||||
}
|
||||
|
||||
NS_ASSERT_MSG(!(*m_presentExt & RADIOTAP_EHT_SIG), "EHT radiotap field already present");
|
||||
*m_presentExt |= RADIOTAP_EHT_SIG;
|
||||
|
||||
m_ehtTlvPad = ((8 - m_length % 8) % 8);
|
||||
m_ehtTlv.type = 32 + std::countr_zero<uint16_t>(RADIOTAP_EHT_SIG);
|
||||
m_ehtTlv.length = (40 + ehtFields.userInfo.size() * 4);
|
||||
m_length += sizeof(TlvFields) + m_ehtTlvPad;
|
||||
|
||||
m_ehtPad = ((4 - m_length % 4) % 4);
|
||||
m_ehtFields = ehtFields;
|
||||
m_length += m_ehtTlv.length + m_ehtPad;
|
||||
|
||||
NS_LOG_LOGIC(this << " m_length=" << m_length << " m_present=0x" << std::hex << m_present
|
||||
<< " m_presentExt=0x" << *m_presentExt << std::dec);
|
||||
}
|
||||
|
||||
void
|
||||
RadiotapHeader::SerializeEht(Buffer::Iterator& start) const
|
||||
{
|
||||
start.WriteU8(0, m_ehtTlvPad);
|
||||
start.WriteU16(m_ehtTlv.type);
|
||||
start.WriteU16(m_ehtTlv.length);
|
||||
start.WriteU8(0, m_ehtPad);
|
||||
start.WriteU32(m_ehtFields.known);
|
||||
for (const auto dataField : m_ehtFields.data)
|
||||
{
|
||||
start.WriteU32(dataField);
|
||||
}
|
||||
for (const auto userInfoField : m_ehtFields.userInfo)
|
||||
{
|
||||
start.WriteU32(userInfoField);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
RadiotapHeader::DeserializeEht(Buffer::Iterator start, uint32_t bytesRead)
|
||||
{
|
||||
const auto startBytesRead = bytesRead;
|
||||
|
||||
m_ehtTlvPad = ((8 - bytesRead % 8) % 8);
|
||||
start.Next(m_ehtTlvPad);
|
||||
bytesRead += m_ehtTlvPad;
|
||||
m_ehtTlv.type = start.ReadU16();
|
||||
m_ehtTlv.length = start.ReadU16();
|
||||
bytesRead += sizeof(TlvFields);
|
||||
|
||||
m_ehtPad = ((4 - bytesRead % 4) % 4);
|
||||
start.Next(m_ehtPad);
|
||||
bytesRead += m_ehtPad;
|
||||
m_ehtFields.known = start.ReadU32();
|
||||
bytesRead += 4;
|
||||
for (auto& dataField : m_ehtFields.data)
|
||||
{
|
||||
dataField = start.ReadU32();
|
||||
bytesRead += 4;
|
||||
}
|
||||
const auto userInfosBytes = m_ehtTlv.length - bytesRead - m_ehtTlvPad;
|
||||
NS_ASSERT(userInfosBytes % 4 == 0);
|
||||
const std::size_t numUsers = userInfosBytes / 4;
|
||||
for (std::size_t i = 0; i < numUsers; ++i)
|
||||
{
|
||||
m_ehtFields.userInfo.push_back(start.ReadU32());
|
||||
bytesRead += 4;
|
||||
}
|
||||
|
||||
return bytesRead - startBytesRead;
|
||||
}
|
||||
|
||||
void
|
||||
RadiotapHeader::PrintEht(std::ostream& os) const
|
||||
{
|
||||
os << " eht.known=0x" << std::hex << m_ehtFields.known;
|
||||
std::size_t index = 0;
|
||||
for (const auto dataField : m_ehtFields.data)
|
||||
{
|
||||
os << " eht.data" << index++ << "=0x" << dataField;
|
||||
}
|
||||
index = 0;
|
||||
for (const auto userInfoField : m_ehtFields.userInfo)
|
||||
{
|
||||
os << " eht.userInfo" << index++ << "=0x" << userInfoField;
|
||||
}
|
||||
os << std::dec;
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <array>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
@@ -592,6 +593,185 @@ class RadiotapHeader : public Header
|
||||
*/
|
||||
void SetUsigFields(const UsigFields& usigFields);
|
||||
|
||||
/**
|
||||
* structure that contains the subfields of the EHT field.
|
||||
*/
|
||||
struct EhtFields
|
||||
{
|
||||
uint32_t known{0}; //!< known field.
|
||||
std::array<uint32_t, 9> data{}; //!< data fields.
|
||||
std::vector<uint32_t> userInfo{}; //!< user info fields.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief EHT known subfield.
|
||||
*/
|
||||
enum EhtKnown : uint32_t
|
||||
{
|
||||
EHT_KNOWN_SPATIAL_REUSE = 0x00000002,
|
||||
EHT_KNOWN_GI = 0x00000004,
|
||||
EHT_KNOWN_EHT_LTF = 0x00000010,
|
||||
EHT_KNOWN_LDPC_EXTRA_SYM_OM = 0x00000020,
|
||||
EHT_KNOWN_PRE_PADD_FACOR_OM = 0x00000040,
|
||||
EHT_KNOWN_PE_DISAMBIGUITY_OM = 0x00000080,
|
||||
EHT_KNOWN_DISREGARD_O = 0x00000100,
|
||||
EHT_KNOWN_DISREGARD_S = 0x00000200,
|
||||
EHT_KNOWN_CRC1 = 0x00002000,
|
||||
EHT_KNOWN_TAIL1 = 0x00004000,
|
||||
EHT_KNOWN_CRC2_O = 0x00008000,
|
||||
EHT_KNOWN_TAIL2_O = 0x00010000,
|
||||
EHT_KNOWN_NSS_S = 0x00020000,
|
||||
EHT_KNOWN_BEAMFORMED_S = 0x00040000,
|
||||
EHT_KNOWN_NR_NON_OFDMA_USERS_M = 0x00080000,
|
||||
EHT_KNOWN_ENCODING_BLOCK_CRC_M = 0x00100000,
|
||||
EHT_KNOWN_ENCODING_BLOCK_TAIL_M = 0x00200000,
|
||||
EHT_KNOWN_RU_MRU_SIZE_OM = 0x00400000,
|
||||
EHT_KNOWN_RU_MRU_INDEX_OM = 0x00800000,
|
||||
EHT_KNOWN_RU_ALLOC_TB_OM = 0x01000000,
|
||||
EHT_KNOWN_PRIMARY_80 = 0x02000000,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief EHT data subfield.
|
||||
*/
|
||||
enum EhtData : uint32_t
|
||||
{
|
||||
/* Data 0 */
|
||||
EHT_DATA0_SPATIAL_REUSE = 0x00000078,
|
||||
EHT_DATA0_GI = 0x00000180,
|
||||
EHT_DATA0_LTF = 0x00000600,
|
||||
EHT_DATA0_EHT_LTF = 0x00003800,
|
||||
EHT_DATA0_LDPC_EXTRA_SYM_OM = 0x00004000,
|
||||
EHT_DATA0_PRE_PADD_FACOR_OM = 0x00018000,
|
||||
EHT_DATA0_PE_DISAMBIGUITY_OM = 0x00020000,
|
||||
EHT_DATA0_DISREGARD_S = 0x000c0000,
|
||||
EHT_DATA0_DISREGARD_O = 0x003c0000,
|
||||
EHT_DATA0_CRC1_O = 0x03c00000,
|
||||
EHT_DATA0_TAIL1_O = 0xfc000000,
|
||||
/* Data 1 */
|
||||
EHT_DATA1_RU_MRU_SIZE = 0x0000001f,
|
||||
EHT_DATA1_RU_MRU_INDEX = 0x00001fe0,
|
||||
EHT_DATA1_RU_ALLOC_CC_1_1_1 = 0x003fe000,
|
||||
EHT_DATA1_RU_ALLOC_CC_1_1_1_KNOWN = 0x00400000,
|
||||
EHT_DATA1_PRIMARY_80 = 0xc0000000,
|
||||
/* Data 2 */
|
||||
EHT_DATA2_RU_ALLOC_CC_2_1_1 = 0x000001ff,
|
||||
EHT_DATA2_RU_ALLOC_CC_2_1_1_KNOWN = 0x00000200,
|
||||
EHT_DATA2_RU_ALLOC_CC_1_1_2 = 0x0007fc00,
|
||||
EHT_DATA2_RU_ALLOC_CC_1_1_2_KNOWN = 0x00080000,
|
||||
EHT_DATA2_RU_ALLOC_CC_2_1_2 = 0x1ff00000,
|
||||
EHT_DATA2_RU_ALLOC_CC_2_1_2_KNOWN = 0x20000000,
|
||||
/* Data 3 */
|
||||
EHT_DATA3_RU_ALLOC_CC_1_2_1 = 0x000001ff,
|
||||
EHT_DATA3_RU_ALLOC_CC_1_2_1_KNOWN = 0x00000200,
|
||||
EHT_DATA3_RU_ALLOC_CC_2_2_1 = 0x0007fc00,
|
||||
EHT_DATA3_RU_ALLOC_CC_2_2_1_KNOWN = 0x00080000,
|
||||
EHT_DATA3_RU_ALLOC_CC_1_2_2 = 0x1ff00000,
|
||||
EHT_DATA3_RU_ALLOC_CC_1_2_2_KNOWN = 0x20000000,
|
||||
/* Data 4 */
|
||||
EHT_DATA4_RU_ALLOC_CC_2_2_2 = 0x000001ff,
|
||||
EHT_DATA4_RU_ALLOC_CC_2_2_2_KNOWN = 0x00000200,
|
||||
EHT_DATA4_RU_ALLOC_CC_1_2_3 = 0x0007fc00,
|
||||
EHT_DATA4_RU_ALLOC_CC_1_2_3_KNOWN = 0x00080000,
|
||||
EHT_DATA4_RU_ALLOC_CC_2_2_3 = 0x1ff00000,
|
||||
EHT_DATA4_RU_ALLOC_CC_2_2_3_KNOWN = 0x20000000,
|
||||
/* Data 5 */
|
||||
EHT_DATA5_RU_ALLOC_CC_1_2_4 = 0x000001ff,
|
||||
EHT_DATA5_RU_ALLOC_CC_1_2_4_KNOWN = 0x00000200,
|
||||
EHT_DATA5_RU_ALLOC_CC_2_2_4 = 0x0007fc00,
|
||||
EHT_DATA5_RU_ALLOC_CC_2_2_4_KNOWN = 0x00080000,
|
||||
EHT_DATA5_RU_ALLOC_CC_1_2_5 = 0x1ff00000,
|
||||
EHT_DATA5_RU_ALLOC_CC_1_2_5_KNOWN = 0x20000000,
|
||||
/* Data 6 */
|
||||
EHT_DATA6_RU_ALLOC_CC_2_2_5 = 0x000001ff,
|
||||
EHT_DATA6_RU_ALLOC_CC_2_2_5_KNOWN = 0x00000200,
|
||||
EHT_DATA6_RU_ALLOC_CC_1_2_6 = 0x0007fc00,
|
||||
EHT_DATA6_RU_ALLOC_CC_1_2_6_KNOWN = 0x00080000,
|
||||
EHT_DATA6_RU_ALLOC_CC_2_2_6 = 0x1ff00000,
|
||||
EHT_DATA6_RU_ALLOC_CC_2_2_6_KNOWN = 0x20000000,
|
||||
/* Data 7 */
|
||||
EHT_DATA7_CRC2_O = 0x0000000f,
|
||||
EHT_DATA7_TAIL_2_O = 0x000003f0,
|
||||
EHT_DATA7_NSS_S = 0x0000f000,
|
||||
EHT_DATA7_BEAMFORMED_S = 0x00010000,
|
||||
EHT_DATA7_NUM_OF_NON_OFDMA_USERS = 0x000e0000,
|
||||
EHT_DATA7_USER_ENCODING_BLOCK_CRC = 0x00f00000,
|
||||
EHT_DATA7_USER_ENCODING_BLOCK_TAIL = 0x3f000000,
|
||||
/* Data 8 */
|
||||
EHT_DATA8_RU_ALLOC_TB_FMT_PS_160 = 0x00000001,
|
||||
EHT_DATA8_RU_ALLOC_TB_FMT_B0 = 0x00000002,
|
||||
EHT_DATA8_RU_ALLOC_TB_FMT_B7_B1 = 0x000001fc,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Possible GI values in EHT data subfield.
|
||||
*/
|
||||
enum EhtData0Gi : uint8_t
|
||||
{
|
||||
EHT_DATA0_GI_800_NS = 0,
|
||||
EHT_DATA0_GI_1600_NS = 1,
|
||||
EHT_DATA0_GI_3200_NS = 2,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Possible Primary 80 MHz Channel Position values in EHT data subfield.
|
||||
*/
|
||||
enum EhtData1Primary80 : uint8_t
|
||||
{
|
||||
EHT_DATA1_PRIMARY_80_LOWEST = 0,
|
||||
EHT_DATA1_PRIMARY_80_HIGHEST = 3,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Possible RU/MRU Size values in EHT data subfield.
|
||||
*/
|
||||
enum EhtData1RuSize : uint8_t
|
||||
{
|
||||
EHT_DATA1_RU_MRU_SIZE_26 = 0,
|
||||
EHT_DATA1_RU_MRU_SIZE_52 = 1,
|
||||
EHT_DATA1_RU_MRU_SIZE_106 = 2,
|
||||
EHT_DATA1_RU_MRU_SIZE_242 = 3,
|
||||
EHT_DATA1_RU_MRU_SIZE_484 = 4,
|
||||
EHT_DATA1_RU_MRU_SIZE_996 = 5,
|
||||
EHT_DATA1_RU_MRU_SIZE_2x996 = 6,
|
||||
EHT_DATA1_RU_MRU_SIZE_4x996 = 7,
|
||||
EHT_DATA1_RU_MRU_SIZE_52_26 = 8,
|
||||
EHT_DATA1_RU_MRU_SIZE_106_26 = 9,
|
||||
EHT_DATA1_RU_MRU_SIZE_484_242 = 10,
|
||||
EHT_DATA1_RU_MRU_SIZE_996_484 = 11,
|
||||
EHT_DATA1_RU_MRU_SIZE_996_484_242 = 12,
|
||||
EHT_DATA1_RU_MRU_SIZE_2x996_484 = 13,
|
||||
EHT_DATA1_RU_MRU_SIZE_3x996 = 14,
|
||||
EHT_DATA1_RU_MRU_SIZE_3x996_484 = 15,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief EHT user_info subfield.
|
||||
*/
|
||||
enum EhtUserInfo : uint32_t
|
||||
{
|
||||
EHT_USER_INFO_STA_ID_KNOWN = 0x00000001,
|
||||
EHT_USER_INFO_MCS_KNOWN = 0x00000002,
|
||||
EHT_USER_INFO_CODING_KNOWN = 0x00000004,
|
||||
EHT_USER_INFO_NSS_KNOWN_O = 0x00000010,
|
||||
EHT_USER_INFO_BEAMFORMING_KNOWN_O = 0x00000020,
|
||||
EHT_USER_INFO_SPATIAL_CONFIG_KNOWN_M = 0x00000040,
|
||||
EHT_USER_INFO_DATA_FOR_USER = 0x00000080,
|
||||
EHT_USER_INFO_STA_ID = 0x0007ff00,
|
||||
EHT_USER_INFO_CODING = 0x00080000,
|
||||
EHT_USER_INFO_MCS = 0x00f00000,
|
||||
EHT_USER_INFO_NSS_O = 0x0f000000,
|
||||
EHT_USER_INFO_BEAMFORMING_O = 0x20000000,
|
||||
EHT_USER_INFO_SPATIAL_CONFIG_M = 0x3f000000,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Set the subfields of the EHT-SIG field
|
||||
*
|
||||
* @param ehtFields The subfields of the EHT-SIG field.
|
||||
*/
|
||||
void SetEhtFields(const EhtFields& ehtFields);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Serialize the Channel radiotap header.
|
||||
@@ -785,6 +965,30 @@ class RadiotapHeader : public Header
|
||||
*/
|
||||
void PrintUsig(std::ostream& os) const;
|
||||
|
||||
/**
|
||||
* Serialize the EHT radiotap header.
|
||||
*
|
||||
* @param start An iterator which points to where the header should be written.
|
||||
*/
|
||||
void SerializeEht(Buffer::Iterator& start) const;
|
||||
|
||||
/**
|
||||
* Deserialize the EHT radiotap header.
|
||||
*
|
||||
* @param start An iterator which points to where the header should be read.
|
||||
* @param bytesRead the number of bytes already read.
|
||||
|
||||
* @returns The number of bytes read.
|
||||
*/
|
||||
uint32_t DeserializeEht(Buffer::Iterator start, uint32_t bytesRead);
|
||||
|
||||
/**
|
||||
* Add EHT subfield/value pairs to the output stream.
|
||||
*
|
||||
* @param os The output stream
|
||||
*/
|
||||
void PrintEht(std::ostream& os) const;
|
||||
|
||||
/**
|
||||
* @brief Radiotap flags.
|
||||
*/
|
||||
@@ -867,6 +1071,11 @@ class RadiotapHeader : public Header
|
||||
TlvFields m_usigTlv{}; //!< U-SIG TLV fields.
|
||||
uint8_t m_usigPad{0}; //!< U-SIG padding.
|
||||
UsigFields m_usigFields{}; //!< U-SIG fields.
|
||||
|
||||
uint8_t m_ehtTlvPad{0}; //!< EHT TLV padding.
|
||||
TlvFields m_ehtTlv{}; //!< EHT TLV fields.
|
||||
uint8_t m_ehtPad{0}; //!< EHT padding.
|
||||
EhtFields m_ehtFields{}; //!< EHT fields.
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
Reference in New Issue
Block a user