network: Add support for EHT field in radiotap header

This commit is contained in:
Sébastien Deronne
2024-10-12 10:09:31 +02:00
parent 18aab3c7ab
commit 82da636bc5
2 changed files with 327 additions and 1 deletions

View File

@@ -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

View File

@@ -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