diff --git a/src/network/utils/radiotap-header.cc b/src/network/utils/radiotap-header.cc index bc9f9e294..e345a1d2c 100644 --- a/src/network/utils/radiotap-header.cc +++ b/src/network/utils/radiotap-header.cc @@ -260,6 +260,15 @@ RadiotapHeader::Serialize(Buffer::Iterator start) const { SerializeHeMuOtherUser(start); } + + // + // U-SIG field. + // Reference: https://www.radiotap.org/fields/U-SIG.html + // + if (m_presentExt && (*m_presentExt & RADIOTAP_USIG)) // bit 33 + { + SerializeUsig(start); + } } uint32_t @@ -502,6 +511,15 @@ RadiotapHeader::Deserialize(Buffer::Iterator start) bytesRead += DeserializeHeMuOtherUser(start, bytesRead); } + // + // U-SIG field. + // Reference: https://www.radiotap.org/fields/U-SIG.html + // + if (m_presentExt && (*m_presentExt & RADIOTAP_USIG)) // bit 33 + { + bytesRead += DeserializeUsig(start, bytesRead); + } + NS_ASSERT_MSG(m_length == bytesRead, "RadiotapHeader::Deserialize(): expected and actual lengths inconsistent"); return bytesRead; @@ -541,6 +559,10 @@ RadiotapHeader::Print(std::ostream& os) const { PrintHeMuOtherUser(os); } + if (m_presentExt && (*m_presentExt & RADIOTAP_USIG)) + { + PrintUsig(os); + } } void @@ -982,4 +1004,70 @@ RadiotapHeader::PrintHeMuOtherUser(std::ostream& os) const << std::dec; } +void +RadiotapHeader::SetUsigFields(const UsigFields& usigFields) +{ + NS_LOG_FUNCTION(this << usigFields.common << usigFields.mask << usigFields.value); + if (!m_presentExt) + { + m_present |= RADIOTAP_TLV | RADIOTAP_EXT; + m_presentExt = 0; + m_length += sizeof(RadiotapExtFlags); + } + + NS_ASSERT_MSG(!(*m_presentExt & RADIOTAP_USIG), "U-SIG radiotap field already present"); + *m_presentExt |= RADIOTAP_USIG; + + m_usigTlvPad = ((8 - m_length % 8) % 8); + m_usigTlv.type = 32 + std::countr_zero(RADIOTAP_USIG); + m_usigTlv.length = sizeof(UsigFields); + m_length += sizeof(TlvFields) + m_usigTlvPad; + + m_usigPad = ((4 - m_length % 4) % 4); + m_usigFields = usigFields; + m_length += m_usigTlv.length + m_usigPad; + + NS_LOG_LOGIC(this << " m_length=" << m_length << " m_present=0x" << std::hex << m_present + << " m_presentExt=0x" << *m_presentExt << std::dec); +} + +void +RadiotapHeader::SerializeUsig(Buffer::Iterator& start) const +{ + start.WriteU8(0, m_usigTlvPad); + start.WriteU16(m_usigTlv.type); + start.WriteU16(m_usigTlv.length); + start.WriteU8(0, m_usigPad); + start.WriteU32(m_usigFields.common); + start.WriteU32(m_usigFields.value); + start.WriteU32(m_usigFields.mask); +} + +uint32_t +RadiotapHeader::DeserializeUsig(Buffer::Iterator start, uint32_t bytesRead) +{ + const auto startBytesRead = bytesRead; + m_usigTlvPad = ((8 - bytesRead % 8) % 8); + start.Next(m_usigTlvPad); + bytesRead += m_usigTlvPad; + m_usigTlv.type = start.ReadU16(); + m_usigTlv.length = start.ReadU16(); + bytesRead += sizeof(TlvFields); + m_usigPad = ((4 - bytesRead % 4) % 4); + start.Next(m_usigPad); + bytesRead += m_usigPad; + m_usigFields.common = start.ReadU32(); + m_usigFields.value = start.ReadU32(); + m_usigFields.mask = start.ReadU32(); + bytesRead += sizeof(UsigFields); + return bytesRead - startBytesRead; +} + +void +RadiotapHeader::PrintUsig(std::ostream& os) const +{ + os << " usig.common=0x" << std::hex << m_usigFields.common << " usig.value=0x" + << m_usigFields.value << " usig.mask=0x" << m_usigFields.mask << std::dec; +} + } // namespace ns3 diff --git a/src/network/utils/radiotap-header.h b/src/network/utils/radiotap-header.h index dd71db62a..07a9d6662 100644 --- a/src/network/utils/radiotap-header.h +++ b/src/network/utils/radiotap-header.h @@ -506,6 +506,92 @@ class RadiotapHeader : public Header uint16_t length{0}; //!< length field. }; + /** + * structure that contains the subfields of the U-SIG field. + */ + struct UsigFields + { + uint32_t common{0}; //!< common field. + uint32_t value{0}; //!< value field. + uint32_t mask{0}; //!< mask field. + }; + + /** + * @brief U-SIG common subfield. + */ + enum UsigCommon : uint32_t + { + USIG_COMMON_PHY_VER_KNOWN = 0x00000001, + USIG_COMMON_BW_KNOWN = 0x00000002, + USIG_COMMON_UL_DL_KNOWN = 0x00000004, + USIG_COMMON_BSS_COLOR_KNOWN = 0x00000008, + USIG_COMMON_TXOP_KNOWN = 0x00000010, + USIG_COMMON_BAD_USIG_CRC = 0x00000020, + USIG_COMMON_VALIDATE_BITS_CHECKED = 0x00000040, + USIG_COMMON_VALIDATE_BITS_OK = 0x00000080, + USIG_COMMON_PHY_VER = 0x00007000, + USIG_COMMON_BW = 0x00038000, + USIG_COMMON_UL_DL = 0x00040000, + USIG_COMMON_BSS_COLOR = 0x01f80000, + USIG_COMMON_TXOP = 0xfe000000, + }; + + /** + * @brief Possible BW values in U-SIG common subfield. + */ + enum UsigCommonBw : uint8_t + { + USIG_COMMON_BW_20MHZ = 0, + USIG_COMMON_BW_40MHZ = 1, + USIG_COMMON_BW_80MHZ = 2, + USIG_COMMON_BW_160MHZ = 3, + USIG_COMMON_BW_320MHZ_1 = 4, + USIG_COMMON_BW_320MHZ_2 = 5, + }; + + /** + * @brief EHT MU PPDU U-SIG contents. + */ + enum UsigMu : uint32_t + { + /* MU-USIG-1 */ + USIG1_MU_B20_B24_DISREGARD = 0x0000001f, + USIG1_MU_B25_VALIDATE = 0x00000020, + /* MU-USIG-2 */ + USIG2_MU_B0_B1_PPDU_TYPE = 0x000000c0, + USIG2_MU_B2_VALIDATE = 0x00000100, + USIG2_MU_B3_B7_PUNCTURED_INFO = 0x00003e00, + USIG2_MU_B8_VALIDATE = 0x00004000, + USIG2_MU_B9_B10_SIG_MCS = 0x00018000, + USIG2_MU_B11_B15_EHT_SYMBOLS = 0x003e0000, + USIG2_MU_B16_B19_CRC = 0x03c00000, + USIG2_MU_B20_B25_TAIL = 0xfc000000, + }; + + /** + * @brief EHT TB PPDU U-SIG contents. + */ + enum UsigTb : uint32_t + { + /* TB-USIG-1 */ + USIG1_TB_B20_B25_DISREGARD = 0x0000001f, + /* TB-USIG-2 */ + USIG2_TB_B0_B1_PPDU_TYPE = 0x000000c0, + USIG2_TB_B2_VALIDATE = 0x00000100, + USIG2_TB_B3_B6_SPATIAL_REUSE_1 = 0x00001e00, + USIG2_TB_B7_B10_SPATIAL_REUSE_2 = 0x0001e000, + USIG2_TB_B11_B15_DISREGARD = 0x003e0000, + USIG2_TB_B16_B19_CRC = 0x03c00000, + USIG2_TB_B20_B25_TAIL = 0xfc000000, + }; + + /** + * @brief Set the subfields of the U-SIG field + * + * @param usigFields The subfields of the U-SIG field. + */ + void SetUsigFields(const UsigFields& usigFields); + private: /** * Serialize the Channel radiotap header. @@ -675,6 +761,30 @@ class RadiotapHeader : public Header */ void PrintHeMuOtherUser(std::ostream& os) const; + /** + * Serialize the U-SIG radiotap header. + * + * @param start An iterator which points to where the header should be written. + */ + void SerializeUsig(Buffer::Iterator& start) const; + + /** + * Deserialize the U-SIG 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 DeserializeUsig(Buffer::Iterator start, uint32_t bytesRead); + + /** + * Add U-SIG subfield/value pairs to the output stream. + * + * @param os The output stream + */ + void PrintUsig(std::ostream& os) const; + /** * @brief Radiotap flags. */ @@ -752,6 +862,11 @@ class RadiotapHeader : public Header uint8_t m_heMuOtherUserPad{0}; //!< HE MU other user padding. HeMuOtherUserFields m_heMuOtherUserFields{}; //!< HE MU other user fields. + + uint8_t m_usigTlvPad{0}; //!< U-SIG TLV padding. + TlvFields m_usigTlv{}; //!< U-SIG TLV fields. + uint8_t m_usigPad{0}; //!< U-SIG padding. + UsigFields m_usigFields{}; //!< U-SIG fields. }; } // namespace ns3 diff --git a/utils/codespell-ignored-words b/utils/codespell-ignored-words index db9f12521..e3a32dd98 100644 --- a/utils/codespell-ignored-words +++ b/utils/codespell-ignored-words @@ -30,6 +30,7 @@ interm #Wi-Fi aci fils +usig #Wimax aas