diff --git a/src/wifi/model/block-ack-type.cc b/src/wifi/model/block-ack-type.cc index af3a226ba..2e754ba24 100644 --- a/src/wifi/model/block-ack-type.cc +++ b/src/wifi/model/block-ack-type.cc @@ -23,6 +23,7 @@ BlockAckType::BlockAckType(Variant v) break; case COMPRESSED: case EXTENDED_COMPRESSED: + case GCR: m_bitmapLen.push_back(8); break; case MULTI_TID: @@ -53,6 +54,7 @@ BlockAckReqType::BlockAckReqType(Variant v) case BASIC: case COMPRESSED: case EXTENDED_COMPRESSED: + case GCR: m_nSeqControls = 1; break; case MULTI_TID: @@ -91,6 +93,9 @@ operator<<(std::ostream& os, const BlockAckType& type) case BlockAckType::MULTI_TID: os << "multi-tid-block-ack[" << type.m_bitmapLen.size() << "]"; break; + case BlockAckType::GCR: + os << "gcr-block-ack"; + break; case BlockAckType::MULTI_STA: os << "multi-sta-block-ack[" << type.m_bitmapLen.size() << "]"; break; @@ -117,6 +122,9 @@ operator<<(std::ostream& os, const BlockAckReqType& type) case BlockAckReqType::MULTI_TID: os << "multi-tid-block-ack-req[" << type.m_nSeqControls << "]"; break; + case BlockAckReqType::GCR: + os << "gcr-block-ack-req"; + break; default: NS_FATAL_ERROR("Unknown block ack request type"); } diff --git a/src/wifi/model/block-ack-type.h b/src/wifi/model/block-ack-type.h index 2fdaea781..c729ca881 100644 --- a/src/wifi/model/block-ack-type.h +++ b/src/wifi/model/block-ack-type.h @@ -26,12 +26,13 @@ struct BlockAckType * @enum Variant * @brief The BlockAck variants */ - enum Variant + enum Variant : uint8_t { BASIC, COMPRESSED, EXTENDED_COMPRESSED, MULTI_TID, + GCR, MULTI_STA }; @@ -68,12 +69,13 @@ struct BlockAckReqType * @enum Variant * @brief The BlockAckReq variants */ - enum Variant + enum Variant : uint8_t { BASIC, COMPRESSED, EXTENDED_COMPRESSED, - MULTI_TID + MULTI_TID, + GCR }; Variant m_variant; //!< Block Ack Request variant diff --git a/src/wifi/model/ctrl-headers.cc b/src/wifi/model/ctrl-headers.cc index 31479be62..bf83e1d19 100644 --- a/src/wifi/model/ctrl-headers.cc +++ b/src/wifi/model/ctrl-headers.cc @@ -72,6 +72,9 @@ CtrlBAckRequestHeader::GetSerializedSize() const case BlockAckReqType::MULTI_TID: size += (2 + 2) * (m_tidInfo + 1); break; + case BlockAckReqType::GCR: + size += (2 + 6); // SSC plus GCR Group Address + break; default: NS_FATAL_ERROR("Invalid BA type"); break; @@ -94,6 +97,10 @@ CtrlBAckRequestHeader::Serialize(Buffer::Iterator start) const case BlockAckReqType::MULTI_TID: NS_FATAL_ERROR("Multi-tid block ack is not supported."); break; + case BlockAckReqType::GCR: + i.WriteHtolsbU16(GetStartingSequenceControl()); + WriteTo(i, m_gcrAddress); + break; default: NS_FATAL_ERROR("Invalid BA type"); break; @@ -115,6 +122,10 @@ CtrlBAckRequestHeader::Deserialize(Buffer::Iterator start) case BlockAckReqType::MULTI_TID: NS_FATAL_ERROR("Multi-tid block ack is not supported."); break; + case BlockAckReqType::GCR: + SetStartingSequenceControl(i.ReadLsbtohU16()); + ReadFrom(i, m_gcrAddress); + break; default: NS_FATAL_ERROR("Invalid BA type"); break; @@ -139,6 +150,9 @@ CtrlBAckRequestHeader::GetBarControl() const case BlockAckReqType::MULTI_TID: res |= (0x03 << 1); break; + case BlockAckReqType::GCR: + res |= (0x06 << 1); + break; default: NS_FATAL_ERROR("Invalid BA type"); break; @@ -151,7 +165,11 @@ void CtrlBAckRequestHeader::SetBarControl(uint16_t bar) { m_barAckPolicy = ((bar & 0x01) == 1); - if (((bar >> 1) & 0x0f) == 0x03) + if (((bar >> 1) & 0x0f) == 0x06) + { + m_barType.m_variant = BlockAckReqType::GCR; + } + else if (((bar >> 1) & 0x0f) == 0x03) { m_barType.m_variant = BlockAckReqType::MULTI_TID; } @@ -231,6 +249,20 @@ CtrlBAckRequestHeader::GetStartingSequence() const return m_startingSeq; } +void +CtrlBAckRequestHeader::SetGcrGroupAddress(const Mac48Address& address) +{ + NS_ASSERT(IsGcr()); + m_gcrAddress = address; +} + +Mac48Address +CtrlBAckRequestHeader::GetGcrGroupAddress() const +{ + NS_ASSERT(IsGcr()); + return m_gcrAddress; +} + bool CtrlBAckRequestHeader::IsBasic() const { @@ -255,6 +287,12 @@ CtrlBAckRequestHeader::IsMultiTid() const return m_barType.m_variant == BlockAckReqType::MULTI_TID; } +bool +CtrlBAckRequestHeader::IsGcr() const +{ + return m_barType.m_variant == BlockAckReqType::GCR; +} + /*********************************** * Block ack response ***********************************/ @@ -323,6 +361,9 @@ CtrlBAckResponseHeader::GetSerializedSize() const case BlockAckType::MULTI_TID: size += (2 + 2 + 8) * (m_tidInfo + 1); // Multi-TID block ack break; + case BlockAckType::GCR: + size += (2 + 6 + m_baType.m_bitmapLen[0]); + break; case BlockAckType::MULTI_STA: for (auto& bitmapLen : m_baType.m_bitmapLen) { @@ -349,6 +390,11 @@ CtrlBAckResponseHeader::Serialize(Buffer::Iterator start) const i.WriteHtolsbU16(GetStartingSequenceControl()); i = SerializeBitmap(i); break; + case BlockAckType::GCR: + i.WriteHtolsbU16(GetStartingSequenceControl()); + WriteTo(i, m_baInfo[0].m_address); + i = SerializeBitmap(i); + break; case BlockAckType::MULTI_STA: for (std::size_t index = 0; index < m_baInfo.size(); index++) { @@ -365,7 +411,7 @@ CtrlBAckResponseHeader::Serialize(Buffer::Iterator start) const { uint32_t reserved = 0; i.WriteHtolsbU32(reserved); - WriteTo(i, m_baInfo[index].m_ra); + WriteTo(i, m_baInfo[index].m_address); } } break; @@ -391,6 +437,11 @@ CtrlBAckResponseHeader::Deserialize(Buffer::Iterator start) SetStartingSequenceControl(i.ReadLsbtohU16()); i = DeserializeBitmap(i); break; + case BlockAckType::GCR: + SetStartingSequenceControl(i.ReadLsbtohU16()); + ReadFrom(i, m_baInfo[0].m_address); + i = DeserializeBitmap(i); + break; case BlockAckType::MULTI_STA: { std::size_t index = 0; while (i.GetRemainingSize() > 0) @@ -414,7 +465,7 @@ CtrlBAckResponseHeader::Deserialize(Buffer::Iterator start) else { i.ReadLsbtohU32(); // next 4 bytes are reserved - ReadFrom(i, m_baInfo.back().m_ra); + ReadFrom(i, m_baInfo.back().m_address); // the length of this Per AID TID Info subfield is 12, so set // the bitmap length to 8 to simulate the correct size m_baType.m_bitmapLen.back() = 8; @@ -450,7 +501,7 @@ CtrlBAckResponseHeader::SetType(BlockAckType type) BaInfoInstance baInfoInstance{.m_aidTidInfo = 0, .m_startingSeq = 0, .m_bitmap = std::vector(bitmapLen, 0), - .m_ra = Mac48Address()}; + .m_address = Mac48Address()}; m_baInfo.emplace_back(baInfoInstance); } @@ -555,6 +606,12 @@ CtrlBAckResponseHeader::IsMultiSta() const return m_baType.m_variant == BlockAckType::MULTI_STA; } +bool +CtrlBAckResponseHeader::IsGcr() const +{ + return m_baType.m_variant == BlockAckType::GCR; +} + void CtrlBAckResponseHeader::SetAid11(uint16_t aid, std::size_t index) { @@ -595,7 +652,7 @@ CtrlBAckResponseHeader::SetUnassociatedStaAddress(const Mac48Address& ra, std::s { NS_ASSERT(GetAid11(index) == 2045); - m_baInfo[index].m_ra = ra; + m_baInfo[index].m_address = ra; } Mac48Address @@ -603,7 +660,7 @@ CtrlBAckResponseHeader::GetUnassociatedStaAddress(std::size_t index) const { NS_ASSERT(GetAid11(index) == 2045); - return m_baInfo[index].m_ra; + return m_baInfo[index].m_address; } std::size_t @@ -630,6 +687,20 @@ CtrlBAckResponseHeader::FindPerAidTidInfoWithAid(uint16_t aid) const return ret; } +void +CtrlBAckResponseHeader::SetGcrGroupAddress(const Mac48Address& address) +{ + NS_ASSERT(IsGcr()); + m_baInfo[0].m_address = address; +} + +Mac48Address +CtrlBAckResponseHeader::GetGcrGroupAddress() const +{ + NS_ASSERT(IsGcr()); + return m_baInfo[0].m_address; +} + uint16_t CtrlBAckResponseHeader::GetBaControl() const { @@ -651,6 +722,9 @@ CtrlBAckResponseHeader::GetBaControl() const case BlockAckType::MULTI_TID: res |= (0x03 << 1); break; + case BlockAckType::GCR: + res |= (0x06 << 1); + break; case BlockAckType::MULTI_STA: res |= (0x0b << 1); break; @@ -669,7 +743,11 @@ void CtrlBAckResponseHeader::SetBaControl(uint16_t ba) { m_baAckPolicy = ((ba & 0x01) == 1); - if (((ba >> 1) & 0x0f) == 0x03) + if (((ba >> 1) & 0x0f) == 0x06) + { + SetType(BlockAckType::GCR); + } + else if (((ba >> 1) & 0x0f) == 0x03) { SetType(BlockAckType::MULTI_TID); } @@ -711,7 +789,7 @@ CtrlBAckResponseHeader::GetStartingSequenceControl(std::size_t index) const // The Fragment Number subfield encodes the length of the bitmap for Compressed and Multi-STA // variants (see sections 9.3.1.8.2 and 9.3.1.8.7 of 802.11ax-2021 and 802.11be Draft 4.0). // Note that Fragmentation Level 3 is not supported. - if (m_baType.m_variant == BlockAckType::COMPRESSED) + if (m_baType.m_variant == BlockAckType::COMPRESSED || m_baType.m_variant == BlockAckType::GCR) { switch (m_baType.m_bitmapLen[0]) { @@ -774,7 +852,7 @@ CtrlBAckResponseHeader::SetStartingSequenceControl(uint16_t seqControl, std::siz // The Fragment Number subfield encodes the length of the bitmap for Compressed and Multi-STA // variants (see sections 9.3.1.8.2 and 9.3.1.8.7 of 802.11ax-2021 and 802.11be Draft 4.0). // Note that Fragmentation Level 3 is not supported. - if (m_baType.m_variant == BlockAckType::COMPRESSED) + if (m_baType.m_variant == BlockAckType::COMPRESSED || m_baType.m_variant == BlockAckType::GCR) { uint16_t fragNumber = seqControl & 0x000f; @@ -785,16 +863,16 @@ CtrlBAckResponseHeader::SetStartingSequenceControl(uint16_t seqControl, std::siz switch (fragNumber) { case 0: - SetType({BlockAckType::COMPRESSED, {8}}); + SetType({m_baType.m_variant, {8}}); break; case 4: - SetType({BlockAckType::COMPRESSED, {32}}); + SetType({m_baType.m_variant, {32}}); break; case 8: - SetType({BlockAckType::COMPRESSED, {64}}); + SetType({m_baType.m_variant, {64}}); break; case 10: - SetType({BlockAckType::COMPRESSED, {128}}); + SetType({m_baType.m_variant, {128}}); break; default: NS_ABORT_MSG("Unsupported fragment number: " << fragNumber); @@ -852,6 +930,7 @@ CtrlBAckResponseHeader::SerializeBitmap(Buffer::Iterator start, std::size_t inde case BlockAckType::BASIC: case BlockAckType::COMPRESSED: case BlockAckType::EXTENDED_COMPRESSED: + case BlockAckType::GCR: case BlockAckType::MULTI_STA: for (const auto& byte : m_baInfo[index].m_bitmap) { @@ -881,6 +960,7 @@ CtrlBAckResponseHeader::DeserializeBitmap(Buffer::Iterator start, std::size_t in case BlockAckType::BASIC: case BlockAckType::COMPRESSED: case BlockAckType::EXTENDED_COMPRESSED: + case BlockAckType::GCR: case BlockAckType::MULTI_STA: for (uint8_t j = 0; j < m_baType.m_bitmapLen[index]; j++) { @@ -917,6 +997,7 @@ CtrlBAckResponseHeader::SetReceivedPacket(uint16_t seq, std::size_t index) break; case BlockAckType::COMPRESSED: case BlockAckType::EXTENDED_COMPRESSED: + case BlockAckType::GCR: case BlockAckType::MULTI_STA: { uint16_t i = IndexInBitmap(seq, index); m_baInfo[index].m_bitmap[i / 8] |= (uint8_t(0x01) << (i % 8)); @@ -946,6 +1027,7 @@ CtrlBAckResponseHeader::SetReceivedFragment(uint16_t seq, uint8_t frag) break; case BlockAckType::COMPRESSED: case BlockAckType::EXTENDED_COMPRESSED: + case BlockAckType::GCR: case BlockAckType::MULTI_STA: /* We can ignore this...compressed block ack doesn't support acknowledgment of single fragments */ @@ -983,6 +1065,7 @@ CtrlBAckResponseHeader::IsPacketReceived(uint16_t seq, std::size_t index) const return false; case BlockAckType::COMPRESSED: case BlockAckType::EXTENDED_COMPRESSED: + case BlockAckType::GCR: case BlockAckType::MULTI_STA: { uint16_t i = IndexInBitmap(seq, index); uint8_t mask = uint8_t(0x01) << (i % 8); @@ -1013,6 +1096,7 @@ CtrlBAckResponseHeader::IsFragmentReceived(uint16_t seq, uint8_t frag) const 0; case BlockAckType::COMPRESSED: case BlockAckType::EXTENDED_COMPRESSED: + case BlockAckType::GCR: case BlockAckType::MULTI_STA: /* We can ignore this...compressed block ack doesn't support acknowledgement of single fragments */ diff --git a/src/wifi/model/ctrl-headers.h b/src/wifi/model/ctrl-headers.h index 29ac2159c..fb85fd46d 100644 --- a/src/wifi/model/ctrl-headers.h +++ b/src/wifi/model/ctrl-headers.h @@ -29,13 +29,13 @@ enum AcIndex : uint8_t; * @ingroup wifi * @brief Headers for BlockAckRequest. * - * 802.11n standard includes three types of BlockAck: - * - Basic BlockAck (unique type in 802.11e) - * - Compressed BlockAck - * - Multi-TID BlockAck - * For now only basic BlockAck and compressed BlockAck - * are supported. - * Basic BlockAck is also default variant. + * 802.11 standard includes multiple BlockAckReq variants: + * - Basic BlockAckReq (unique type in 802.11e) + * - Compressed BlockAckReq + * - Multi-TID BlockAckReq + * - GCR BlockAckReq + * For now only basic BlockAckReq, compressed BlockAckReq and GCR BlockAckReq are supported. + * Basic BlockAckReq is the default variant. */ class CtrlBAckRequestHeader : public Header { @@ -79,6 +79,12 @@ class CtrlBAckRequestHeader : public Header * @param seq the raw sequence control */ void SetStartingSequence(uint16_t seq); + /** + * Set the GCR Group address (GCR variant only). + * + * @param address the GCR Group Address + */ + void SetGcrGroupAddress(const Mac48Address& address); /** * Check if the current Ack Policy is immediate. @@ -106,35 +112,29 @@ class CtrlBAckRequestHeader : public Header */ uint16_t GetStartingSequence() const; /** - * Check if the current Ack Policy is Basic Block Ack - * (i.e. not multi-TID nor compressed). - * - * @return true if the current Ack Policy is Basic Block Ack, - * false otherwise + * @return the GCR Group Address (GCR variant only) + */ + Mac48Address GetGcrGroupAddress() const; + /** + * @return whether the variant of this BlockAckReq is Basic */ bool IsBasic() const; /** - * Check if the current Ack Policy is Compressed Block Ack - * and not multi-TID. - * - * @return true if the current Ack Policy is Compressed Block Ack, - * false otherwise + * @return whether the variant of this BlockAckReq is Compressed */ bool IsCompressed() const; /** - * Check if the current Ack Policy is Extended Compressed Block Ack. - * - * @return true if the current Ack Policy is Extended Compressed Block Ack, - * false otherwise + * @return whether the variant of this BlockAckReq is Extended Compressed */ bool IsExtendedCompressed() const; /** - * Check if the current Ack Policy has Multi-TID Block Ack. - * - * @return true if the current Ack Policy has Multi-TID Block Ack, - * false otherwise + * @return whether the variant of this BlockAckReq is Multi-TID */ bool IsMultiTid() const; + /** + * @return whether the variant of this BlockAckReq is GCR + */ + bool IsGcr() const; /** * Return the starting sequence control. @@ -174,17 +174,20 @@ class CtrlBAckRequestHeader : public Header BlockAckReqType m_barType; ///< BAR type uint16_t m_tidInfo; ///< TID info uint16_t m_startingSeq; ///< starting seq + Mac48Address m_gcrAddress; ///< GCR Group Address (GCR variant only) }; /** * @ingroup wifi * @brief Headers for BlockAck response. * - * 802.11n standard includes three types of BlockAck: + * 802.11 standard includes multiple BlockAck variants: * - Basic BlockAck (unique type in 802.11e) * - Compressed BlockAck * - Multi-TID BlockAck - * For now only basic BlockAck and compressed BlockAck + * - GCR BlockAck + * - Multi-STA BlockAck + * For now only basic BlockAck, compressed BlockAck, GCR BlockAck and Multi-STA BlockAck * are supported. * Basic BlockAck is also default variant. */ @@ -236,6 +239,12 @@ class CtrlBAckResponseHeader : public Header * @param index the index of the Per AID TID Info subfield (Multi-STA Block Ack only) */ void SetStartingSequence(uint16_t seq, std::size_t index = 0); + /** + * Set the GCR Group address (GCR variant only). + * + * @param address the GCR Group Address + */ + void SetGcrGroupAddress(const Mac48Address& address); /** * Check if the current Ack Policy is immediate. @@ -270,38 +279,31 @@ class CtrlBAckResponseHeader : public Header */ uint16_t GetStartingSequence(std::size_t index = 0) const; /** - * Check if the current BA policy is Basic Block Ack. - * - * @return true if the current BA policy is Basic Block Ack, - * false otherwise + * @return the GCR Group Address (GCR variant only) + */ + Mac48Address GetGcrGroupAddress() const; + /** + * @return whether the variant of this BlockAckReq is Basic */ bool IsBasic() const; /** - * Check if the current BA policy is Compressed Block Ack. - * - * @return true if the current BA policy is Compressed Block Ack, - * false otherwise + * @return whether the variant of this BlockAckReq is Compressed */ bool IsCompressed() const; /** - * Check if the current BA policy is Extended Compressed Block Ack. - * - * @return true if the current BA policy is Extended Compressed Block Ack, - * false otherwise + * @return whether the variant of this BlockAckReq is Extended Compressed */ bool IsExtendedCompressed() const; /** - * Check if the current BA policy is Multi-TID Block Ack. - * - * @return true if the current BA policy is Multi-TID Block Ack, - * false otherwise + * @return whether the variant of this BlockAckReq is Multi-TID */ bool IsMultiTid() const; /** - * Check if the BlockAck frame variant is Multi-STA Block Ack. - * - * @return true if the BlockAck frame variant is Multi-STA Block Ack, - * false otherwise + * @return whether the variant of this BlockAckReq is GCR + */ + bool IsGcr() const; + /** + * @return whether the variant of this BlockAckReq is Multi-STA */ bool IsMultiSta() const; @@ -534,8 +536,9 @@ class CtrlBAckResponseHeader : public Header //!< AID TID Info subfield for Multi-STA uint16_t m_startingSeq; //!< Block Ack Starting Sequence Control subfield std::vector m_bitmap; //!< block ack bitmap - Mac48Address m_ra; //!< RA subfield (address of an unassociated station) - //!< for Multi-STA; reserved for other variants + Mac48Address m_address; //!< RA subfield (address of an unassociated station) for + //!< Multi-STA variant; GCR Group Address subfield for GCR + //!< variant; reserved for other variants }; std::vector m_baInfo; //!< BA Information field