From e95689673e5a445a661950cb02a15d7f46d21d24 Mon Sep 17 00:00:00 2001 From: Sharan Naribole Date: Mon, 6 May 2024 13:19:32 +0200 Subject: [PATCH] wifi: Add Probe Request MLE variant --- src/wifi/model/eht/multi-link-element.cc | 84 ++++++++++++++++++++++++ src/wifi/model/eht/multi-link-element.h | 48 +++++++++++++- src/wifi/model/mgt-headers.cc | 57 +++++++++++++++- src/wifi/model/mgt-headers.h | 33 +++++++++- 4 files changed, 217 insertions(+), 5 deletions(-) diff --git a/src/wifi/model/eht/multi-link-element.cc b/src/wifi/model/eht/multi-link-element.cc index 5b125f5e1..1e4934b63 100644 --- a/src/wifi/model/eht/multi-link-element.cc +++ b/src/wifi/model/eht/multi-link-element.cc @@ -9,10 +9,13 @@ #include "multi-link-element.h" #include "ns3/address-utils.h" +#include "ns3/log.h" #include "ns3/mgt-headers.h" #include +NS_LOG_COMPONENT_DEFINE("MultiLinkElement"); + namespace ns3 { @@ -58,6 +61,9 @@ MultiLinkElement::SetVariant(Variant variant) case BASIC_VARIANT: m_commonInfo = CommonInfoBasicMle(); break; + case PROBE_REQUEST_VARIANT: + m_commonInfo = CommonInfoProbeReqMle(); + break; default: NS_ABORT_MSG("Unsupported variant: " << +variant); } @@ -401,9 +407,39 @@ MultiLinkElement::PerStaProfileSubelement::GetAssocResponse() const return *std::get>(m_staProfile); } +void +MultiLinkElement::PerStaProfileSubelement::SetProbeResponse(const MgtProbeResponseHeader& probeResp) +{ + m_staProfile = std::make_unique(probeResp); +} + +void +MultiLinkElement::PerStaProfileSubelement::SetProbeResponse(MgtProbeResponseHeader&& probeResp) +{ + m_staProfile = std::make_unique(std::move(probeResp)); +} + +bool +MultiLinkElement::PerStaProfileSubelement::HasProbeResponse() const +{ + return std::holds_alternative>(m_staProfile); +} + +MgtProbeResponseHeader& +MultiLinkElement::PerStaProfileSubelement::GetProbeResponse() const +{ + NS_ABORT_IF(!HasProbeResponse()); + return *std::get>(m_staProfile); +} + uint8_t MultiLinkElement::PerStaProfileSubelement::GetStaInfoLength() const { + if (m_variant == PROBE_REQUEST_VARIANT) + { + return 0; // IEEE 802.11be 6.0 Figure 9-1072s + } + uint8_t ret = 1; // STA Info Length if (HasStaMacAddress()) @@ -453,6 +489,13 @@ MultiLinkElement::PerStaProfileSubelement::GetInformationFieldSize() const void MultiLinkElement::PerStaProfileSubelement::SerializeInformationField(Buffer::Iterator start) const { + if (m_variant == PROBE_REQUEST_VARIANT) + { + NS_ASSERT_MSG(IsCompleteProfileSet(), "Encoding of STA Profile not supported"); + start.WriteHtolsbU16(m_staControl); + return; + } + start.WriteHtolsbU16(m_staControl); start.WriteU8(GetStaInfoLength()); @@ -486,6 +529,11 @@ uint16_t MultiLinkElement::PerStaProfileSubelement::DeserializeInformationField(Buffer::Iterator start, uint16_t length) { + if (m_variant == PROBE_REQUEST_VARIANT) + { + return DeserProbeReqMlePerSta(start, length); + } + Buffer::Iterator i = start; m_staControl = i.ReadLsbtohU16(); @@ -522,6 +570,42 @@ MultiLinkElement::PerStaProfileSubelement::DeserializeInformationField(Buffer::I return count; } +uint16_t +MultiLinkElement::PerStaProfileSubelement::DeserProbeReqMlePerSta(ns3::Buffer::Iterator start, + uint16_t length) +{ + NS_ASSERT_MSG(m_variant == PROBE_REQUEST_VARIANT, + "Invalid Multi-link Element variant = " << static_cast(m_variant)); + Buffer::Iterator i = start; + uint16_t count = 0; + + m_staControl = i.ReadLsbtohU16(); + count += 2; + + NS_ASSERT_MSG(count <= length, + "Incorrect decoded size count =" << count << ", length=" << length); + if (count == length) + { + return count; + } + + // TODO: Support decoding of Partial Per-STA Profile + // IEEE 802.11be D5.0 9.4.2.312.3 Probe Request Multi-Link element + // If the Complete Profile Requested subfield is set to 0 and the STA Profile field + // is present in a Per-STA Profile subelement, + // the STA Profile field includes exactly one of the following: + // - one Request element (see 9.4.2.9 (Request element)), or + // — one Extended Request element (see 9.4.2.10 (Extended Request element)), or + // — one Request element and one Extended Request element + NS_LOG_DEBUG("Decoding of STA Profile in Per-STA Profile subelement not supported"); + while (count < length) + { + i.ReadU8(); + count++; + } + return count; +} + void MultiLinkElement::AddPerStaProfileSubelement() { diff --git a/src/wifi/model/eht/multi-link-element.h b/src/wifi/model/eht/multi-link-element.h index bf24f01dc..f3fe69255 100644 --- a/src/wifi/model/eht/multi-link-element.h +++ b/src/wifi/model/eht/multi-link-element.h @@ -10,6 +10,7 @@ #define MULTI_LINK_ELEMENT_H #include "common-info-basic-mle.h" +#include "common-info-probe-req-mle.h" #include "ns3/nstime.h" #include "ns3/wifi-information-element.h" @@ -25,6 +26,7 @@ namespace ns3 class MgtAssocRequestHeader; class MgtReassocRequestHeader; class MgtAssocResponseHeader; +class MgtProbeResponseHeader; /// variant holding a reference to a (Re)Association Request using AssocReqRefVariant = std::variant, @@ -56,7 +58,7 @@ class MultiLinkElement : public WifiInformationElement enum Variant : uint8_t { BASIC_VARIANT = 0, - // PROBE_REQUEST_VARIANT, + PROBE_REQUEST_VARIANT, // RECONFIGURATION_VARIANT, // TDLS_VARIANT, // PRIORITY_ACCESS_VARIANT, @@ -76,7 +78,8 @@ class MultiLinkElement : public WifiInformationElement using ContainingFrame = std::variant, std::reference_wrapper, - std::reference_wrapper>; + std::reference_wrapper, + std::reference_wrapper>; /** * Construct a Multi-Link Element with no variant set. @@ -388,6 +391,33 @@ class MultiLinkElement : public WifiInformationElement */ MgtAssocResponseHeader& GetAssocResponse() const; + /** + * Include the given Probe Response frame body in the STA Profile field + * of this Per-STA Profile subelement + * + * @param probeResp the given Probe Response frame body + */ + void SetProbeResponse(const MgtProbeResponseHeader& probeResp); + + /// @copydoc SetProbeResponse + void SetProbeResponse(MgtProbeResponseHeader&& probeResp); + + /** + * Return true if a Probe Response frame body is included in the + * STA Profile field of this Per-STA Profile subelement + * + * @return true if a Probe Response frame body is included + */ + bool HasProbeResponse() const; + + /** + * Get the Probe Response frame body included in the STA Profile + * field of this Per-STA Profile subelement + * + * @return the Probe Response frame body + */ + MgtProbeResponseHeader& GetProbeResponse() const; + /** * Get the size in bytes of the serialized STA Info Length subfield of * the STA Info field @@ -404,13 +434,24 @@ class MultiLinkElement : public WifiInformationElement void SerializeInformationField(Buffer::Iterator start) const override; uint16_t DeserializeInformationField(Buffer::Iterator start, uint16_t length) override; + /** + * Deserialize information of Per-STA Profile Subelement in Probe Request Multi-link + * Element. + * + * @param start an iterator which points to where the information should be written + * @param length the expected number of octets to read + * @return the number of octets read + */ + uint16_t DeserProbeReqMlePerSta(ns3::Buffer::Iterator start, uint16_t length); + Variant m_variant; //!< Multi-Link element variant uint16_t m_staControl; //!< STA Control field Mac48Address m_staMacAddress; //!< STA MAC address std::variant, std::unique_ptr, - std::unique_ptr> + std::unique_ptr, + std::unique_ptr> m_staProfile; /**< STA Profile field, containing the frame body of a frame of the same type as the frame containing the Multi-Link Element */ }; @@ -450,6 +491,7 @@ class MultiLinkElement : public WifiInformationElement /// Typedef for structure holding a Common Info field using CommonInfo = std::variant; diff --git a/src/wifi/model/mgt-headers.cc b/src/wifi/model/mgt-headers.cc index afc0ecfa6..3ce974f97 100644 --- a/src/wifi/model/mgt-headers.cc +++ b/src/wifi/model/mgt-headers.cc @@ -93,6 +93,8 @@ MgtProbeResponseHeader::GetTimestamp() const uint32_t MgtProbeResponseHeader::GetSerializedSizeImpl() const { + SetMleContainingFrame(); + uint32_t size = 8 /* timestamp */ + 2 /* beacon interval */; size += m_capability.GetSerializedSize(); size += WifiMgtHeader::GetSerializedSizeImpl(); @@ -102,6 +104,8 @@ MgtProbeResponseHeader::GetSerializedSizeImpl() const void MgtProbeResponseHeader::SerializeImpl(Buffer::Iterator start) const { + SetMleContainingFrame(); + Buffer::Iterator i = start; i.WriteHtolsbU64(Simulator::Now().GetMicroSeconds()); i.WriteHtolsbU16(static_cast(m_beaconInterval / 1024)); @@ -118,7 +122,20 @@ MgtProbeResponseHeader::DeserializeImpl(Buffer::Iterator start) m_beaconInterval *= 1024; i = m_capability.Deserialize(i); auto distance = i.GetDistanceFrom(start); - return distance + WifiMgtHeader::DeserializeImpl(i); + distance += WifiMgtHeader::DeserializeImpl(i); + if (auto& mle = Get()) + { + for (std::size_t id = 0; id < mle->GetNPerStaProfileSubelements(); ++id) + { + auto& perStaProfile = mle->GetPerStaProfile(id); + if (perStaProfile.HasProbeResponse()) + { + auto& frameInPerStaProfile = perStaProfile.GetProbeResponse(); + frameInPerStaProfile.CopyIesFromContainingFrame(*this); + } + } + } + return distance; } /*********************************************************** @@ -270,6 +287,44 @@ MgtAssocRequestHeader::DeserializeFromPerStaProfileImpl(Buffer::Iterator start, DeserializeFromPerStaProfileImpl(i, length - distance, frame); } +uint32_t +MgtProbeResponseHeader::GetSerializedSizeInPerStaProfileImpl( + const MgtProbeResponseHeader& frame) const +{ + uint32_t size = 0; + size += m_capability.GetSerializedSize(); + size += + MgtHeaderInPerStaProfile::GetSerializedSizeInPerStaProfileImpl(frame); + return size; +} + +void +MgtProbeResponseHeader::SerializeInPerStaProfileImpl(Buffer::Iterator start, + const MgtProbeResponseHeader& frame) const +{ + auto i = start; + i = m_capability.Serialize(i); + MgtHeaderInPerStaProfile::SerializeInPerStaProfileImpl(i, frame); +} + +uint32_t +MgtProbeResponseHeader::DeserializeFromPerStaProfileImpl(Buffer::Iterator start, + uint16_t length, + const MgtProbeResponseHeader& frame) +{ + auto i = start; + m_timestamp = frame.GetTimestamp(); + m_beaconInterval = frame.GetBeaconIntervalUs(); + i = m_capability.Deserialize(i); + auto distance = i.GetDistanceFrom(start); + NS_ASSERT_MSG(distance <= length, + "Bytes read (" << distance << ") exceed expected number (" << length << ")"); + return distance + MgtHeaderInPerStaProfile:: + DeserializeFromPerStaProfileImpl(i, length - distance, frame); +} + /*********************************************************** * Ressoc Request ***********************************************************/ diff --git a/src/wifi/model/mgt-headers.h b/src/wifi/model/mgt-headers.h index c509722d4..7954814d7 100644 --- a/src/wifi/model/mgt-headers.h +++ b/src/wifi/model/mgt-headers.h @@ -87,6 +87,7 @@ using ProbeRequestElems = std::tuple, std::optional, std::optional, + std::optional, std::optional>; /// List of Information Elements included in Probe Response frames @@ -441,9 +442,11 @@ class MgtProbeRequestHeader : public WifiMgtHeader +class MgtProbeResponseHeader + : public MgtHeaderInPerStaProfile { friend class WifiMgtHeader; + friend class MgtHeaderInPerStaProfile; public: ~MgtProbeResponseHeader() override = default; @@ -492,6 +495,34 @@ class MgtProbeResponseHeader : public WifiMgtHeader