diff --git a/src/wifi/CMakeLists.txt b/src/wifi/CMakeLists.txt index 08922bb1a..c533f771d 100644 --- a/src/wifi/CMakeLists.txt +++ b/src/wifi/CMakeLists.txt @@ -91,6 +91,7 @@ set(source_files model/rate-control/rrpaa-wifi-manager.cc model/rate-control/thompson-sampling-wifi-manager.cc model/recipient-block-ack-agreement.cc + model/reduced-neighbor-report.cc model/simple-frame-capture-model.cc model/snr-tag.cc model/spectrum-wifi-phy.cc @@ -229,6 +230,7 @@ set(header_files model/rate-control/rrpaa-wifi-manager.h model/rate-control/thompson-sampling-wifi-manager.h model/recipient-block-ack-agreement.h + model/reduced-neighbor-report.h model/reference/error-rate-tables.h model/simple-frame-capture-model.h model/snr-tag.h diff --git a/src/wifi/model/reduced-neighbor-report.cc b/src/wifi/model/reduced-neighbor-report.cc new file mode 100644 index 000000000..9b088ca50 --- /dev/null +++ b/src/wifi/model/reduced-neighbor-report.cc @@ -0,0 +1,696 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2021 Universita' degli Studi di Napoli Federico II + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Stefano Avallone + */ + +#include "reduced-neighbor-report.h" +#include "wifi-phy-operating-channel.h" +#include "ns3/abort.h" +#include "ns3/address-utils.h" +#include + +namespace ns3 { + +ReducedNeighborReport::ReducedNeighborReport () +{ +} + +WifiInformationElementId +ReducedNeighborReport::ElementId () const +{ + return IE_REDUCED_NEIGHBOR_REPORT; +} + +std::size_t +ReducedNeighborReport::GetNNbrApInfoFields (void) const +{ + return m_nbrApInfoFields.size (); +} + +void +ReducedNeighborReport::AddNbrApInfoField (void) +{ + m_nbrApInfoFields.push_back (NeighborApInformation ()); +} + +void +ReducedNeighborReport::SetOperatingChannel (std::size_t nbrApInfoId, + const WifiPhyOperatingChannel& channel) +{ + NS_ASSERT (nbrApInfoId < m_nbrApInfoFields.size ()); + + uint8_t operatingClass = 0; + uint8_t channelNumber = channel.GetNumber (); + + // Information taken from Table E-4 of 802.11-2020 + switch (channel.GetPhyBand ()) + { + case WIFI_PHY_BAND_2_4GHZ: + if (channel.GetWidth () == 20) + { + operatingClass = 81; + } + else if (channel.GetWidth () == 40) + { + operatingClass = 83; + } + break; + case WIFI_PHY_BAND_5GHZ: + if (channel.GetWidth () == 20) + { + if (channelNumber == 36 || channelNumber == 40 + || channelNumber == 44 || channelNumber == 48) + { + operatingClass = 115; + } + else if (channelNumber == 52 || channelNumber == 56 + || channelNumber == 60 || channelNumber == 64) + { + operatingClass = 118; + } + else if (channelNumber == 100 || channelNumber == 104 || channelNumber == 108 + || channelNumber == 112 || channelNumber == 116 || channelNumber == 120 + || channelNumber == 124 || channelNumber == 128 || channelNumber == 132 + || channelNumber == 136 || channelNumber == 140 || channelNumber == 144) + { + operatingClass = 121; + } + else if (channelNumber == 149 || channelNumber == 153 || channelNumber == 157 + || channelNumber == 161 || channelNumber == 165 || channelNumber == 169 + || channelNumber == 173 || channelNumber == 177 || channelNumber == 181) + { + operatingClass = 125; + } + } + else if (channel.GetWidth () == 40) + { + if (channelNumber == 38 || channelNumber == 46) + { + operatingClass = 116; + } + else if (channelNumber == 54 || channelNumber == 62) + { + operatingClass = 119; + } + else if (channelNumber == 102 || channelNumber == 110 || channelNumber == 118 + || channelNumber == 126 || channelNumber == 134 || channelNumber == 142) + { + operatingClass = 122; + } + else if (channelNumber == 151 || channelNumber == 159 + || channelNumber == 167 || channelNumber == 175) + { + operatingClass = 126; + } + } + else if (channel.GetWidth () == 80) + { + if (channelNumber == 42 || channelNumber == 58 || channelNumber == 106 + || channelNumber == 122 || channelNumber == 138 || channelNumber == 155 + || channelNumber == 171) + { + operatingClass = 128; + } + } + else if (channel.GetWidth () == 160) + { + if (channelNumber == 50 || channelNumber == 114 || channelNumber == 163) + { + operatingClass = 129; + } + } + break; + case WIFI_PHY_BAND_6GHZ: + if (channel.GetWidth () == 20) + { + operatingClass = 131; + } + else if (channel.GetWidth () == 40) + { + operatingClass = 132; + } + else if (channel.GetWidth () == 80) + { + operatingClass = 133; + } + else if (channel.GetWidth () == 160) + { + operatingClass = 134; + } + break; + case WIFI_PHY_BAND_UNSPECIFIED: + NS_ABORT_MSG ("The provided channel has an unspecified PHY band"); + break; + } + + NS_ABORT_MSG_IF (operatingClass == 0, "Operating class not found for channel number " + << channelNumber << " width " << channel.GetWidth () << " MHz " + << "band " << channel.GetPhyBand ()); + + // find the primary channel number + uint16_t startingFreq = 0; + + switch (channel.GetPhyBand ()) + { + case WIFI_PHY_BAND_2_4GHZ: + startingFreq = 2407; + break; + case WIFI_PHY_BAND_5GHZ: + startingFreq = 5000; + break; + case WIFI_PHY_BAND_6GHZ: + startingFreq = 5940; + break; + case WIFI_PHY_BAND_UNSPECIFIED: + NS_ABORT_MSG ("The provided channel has an unspecified PHY band"); + break; + } + + uint8_t primaryChannelNumber = (channel.GetPrimaryChannelCenterFrequency (20) - startingFreq) / 5; + + m_nbrApInfoFields.at (nbrApInfoId).operatingClass = operatingClass; + m_nbrApInfoFields.at (nbrApInfoId).channelNumber = primaryChannelNumber; +} + +WifiPhyOperatingChannel +ReducedNeighborReport::GetOperatingChannel (std::size_t nbrApInfoId) const +{ + NS_ASSERT (nbrApInfoId < m_nbrApInfoFields.size ()); + + WifiPhyBand band = WIFI_PHY_BAND_UNSPECIFIED; + uint16_t width = 0; + + switch (m_nbrApInfoFields.at (nbrApInfoId).operatingClass) + { + case 81: + band = WIFI_PHY_BAND_2_4GHZ; + width = 20; + break; + case 83: + band = WIFI_PHY_BAND_2_4GHZ; + width = 40; + break; + case 115: + case 118: + case 121: + case 125: + band = WIFI_PHY_BAND_5GHZ; + width = 20; + break; + case 116: + case 119: + case 122: + case 126: + band = WIFI_PHY_BAND_5GHZ; + width = 40; + break; + case 128: + band = WIFI_PHY_BAND_5GHZ; + width = 80; + break; + case 129: + band = WIFI_PHY_BAND_5GHZ; + width = 160; + break; + case 131: + band = WIFI_PHY_BAND_6GHZ; + width = 20; + break; + case 132: + band = WIFI_PHY_BAND_6GHZ; + width = 40; + break; + case 133: + band = WIFI_PHY_BAND_6GHZ; + width = 80; + break; + case 134: + band = WIFI_PHY_BAND_6GHZ; + width = 160; + break; + default: + break; + } + + NS_ABORT_IF (band == WIFI_PHY_BAND_UNSPECIFIED || width == 0); + + uint16_t startingFreq = 0; + + switch (band) + { + case WIFI_PHY_BAND_2_4GHZ: + startingFreq = 2407; + break; + case WIFI_PHY_BAND_5GHZ: + startingFreq = 5000; + break; + case WIFI_PHY_BAND_6GHZ: + startingFreq = 5940; + break; + case WIFI_PHY_BAND_UNSPECIFIED: + NS_ABORT_MSG ("Unspecified band"); + break; + } + + uint8_t primaryChannelNumber = m_nbrApInfoFields.at (nbrApInfoId).channelNumber; + uint16_t primaryChannelCenterFrequency = startingFreq + primaryChannelNumber * 5; + + uint8_t channelNumber = 0; + uint16_t frequency = 0; + + for (const auto& channel : WifiPhyOperatingChannel::m_frequencyChannels) + { + if (std::get<2> (channel) == width + && std::get<3> (channel) == WIFI_PHY_OFDM_CHANNEL + && std::get<4> (channel) == band + && primaryChannelCenterFrequency > std::get<1> (channel) - width / 2 + && primaryChannelCenterFrequency < std::get<1> (channel) + width / 2) + { + channelNumber = std::get<0> (channel); + frequency = std::get<1> (channel); + break; + } + } + + NS_ABORT_IF (channelNumber == 0 || frequency == 0); + + WifiPhyOperatingChannel channel; + channel.Set (channelNumber, frequency, width, WIFI_STANDARD_UNSPECIFIED, band); + + uint16_t channelLowestFreq = frequency - width / 2; + uint16_t primaryChannelLowestFreq = primaryChannelCenterFrequency - 10; + channel.SetPrimary20Index ((primaryChannelLowestFreq - channelLowestFreq) / 20); + + return channel; +} + +std::size_t +ReducedNeighborReport::GetNTbttInformationFields (std::size_t nbrApInfoId) const +{ + NS_ASSERT (nbrApInfoId < m_nbrApInfoFields.size ()); + return m_nbrApInfoFields.at (nbrApInfoId).tbttInformationSet.size (); +} + +void +ReducedNeighborReport::AddTbttInformationField (std::size_t nbrApInfoId) +{ + NS_ASSERT (nbrApInfoId < m_nbrApInfoFields.size ()); + m_nbrApInfoFields.at (nbrApInfoId).tbttInformationSet.push_back (TbttInformation ()); + + // set the TBTT Information Count field + m_nbrApInfoFields.at (nbrApInfoId).tbttInfoHdr.tbttInfoCount = m_nbrApInfoFields.at (nbrApInfoId).tbttInformationSet.size () - 1; +} + +void +ReducedNeighborReport::WriteTbttInformationLength (std::size_t nbrApInfoId) const +{ + NS_ASSERT (nbrApInfoId < m_nbrApInfoFields.size ()); + + uint8_t length = 0; // reserved value + + auto it = std::next (m_nbrApInfoFields.begin (), nbrApInfoId); + + if (it->hasBssid + && !it->hasShortSsid + && !it->hasBssParams + && !it->has20MHzPsd + && !it->hasMldParams) + { + length = 7; + } + else if (it->hasBssid + && it->hasShortSsid + && it->hasBssParams + && it->has20MHzPsd + && it->hasMldParams) + { + length = 16; + } + else + { + NS_ABORT_MSG ("Unsupported TBTT Information field contents"); + } + + // set the TBTT Information Length field + it->tbttInfoHdr.tbttInfoLength = length; +} + +void +ReducedNeighborReport::ReadTbttInformationLength (std::size_t nbrApInfoId) +{ + NS_ASSERT (nbrApInfoId < m_nbrApInfoFields.size ()); + + auto it = std::next (m_nbrApInfoFields.begin (), nbrApInfoId); + + switch (it->tbttInfoHdr.tbttInfoLength) + { + case 7: + it->hasBssid = true; + it->hasShortSsid = false; + it->hasBssParams = false; + it->has20MHzPsd = false; + it->hasMldParams = false; + break; + case 16: + it->hasBssid = true; + it->hasShortSsid = true; + it->hasBssParams = true; + it->has20MHzPsd = true; + it->hasMldParams = true; + break; + default: + NS_ABORT_MSG ("Unsupported TBTT Information Length value: " + << it->tbttInfoHdr.tbttInfoLength); + } +} + +void +ReducedNeighborReport::SetBssid (std::size_t nbrApInfoId, std::size_t index, Mac48Address bssid) +{ + NS_ASSERT (nbrApInfoId < m_nbrApInfoFields.size ()); + NS_ASSERT (index < m_nbrApInfoFields.at (nbrApInfoId).tbttInformationSet.size ()); + + m_nbrApInfoFields.at (nbrApInfoId).tbttInformationSet.at (index).bssid = bssid; + + m_nbrApInfoFields.at (nbrApInfoId).hasBssid = true; +} + +bool +ReducedNeighborReport::HasBssid (std::size_t nbrApInfoId) const +{ + NS_ASSERT (nbrApInfoId < m_nbrApInfoFields.size ()); + + return m_nbrApInfoFields.at (nbrApInfoId).hasBssid; +} + +Mac48Address +ReducedNeighborReport::GetBssid (std::size_t nbrApInfoId, std::size_t index) const +{ + NS_ASSERT (HasBssid (nbrApInfoId)); + NS_ASSERT (index < m_nbrApInfoFields.at (nbrApInfoId).tbttInformationSet.size ()); + + return m_nbrApInfoFields.at (nbrApInfoId).tbttInformationSet.at (index).bssid; +} + +void +ReducedNeighborReport::SetShortSsid (std::size_t nbrApInfoId, std::size_t index, uint32_t shortSsid) +{ + NS_ASSERT (nbrApInfoId < m_nbrApInfoFields.size ()); + NS_ASSERT (index < m_nbrApInfoFields.at (nbrApInfoId).tbttInformationSet.size ()); + + m_nbrApInfoFields.at (nbrApInfoId).tbttInformationSet.at (index).shortSsid = shortSsid; + + m_nbrApInfoFields.at (nbrApInfoId).hasShortSsid = true; +} + +bool +ReducedNeighborReport::HasShortSsid (std::size_t nbrApInfoId) const +{ + NS_ASSERT (nbrApInfoId < m_nbrApInfoFields.size ()); + + return m_nbrApInfoFields.at (nbrApInfoId).hasShortSsid; +} + +uint32_t +ReducedNeighborReport::GetShortSsid (std::size_t nbrApInfoId, std::size_t index) const +{ + NS_ASSERT (HasShortSsid (nbrApInfoId)); + NS_ASSERT (index < m_nbrApInfoFields.at (nbrApInfoId).tbttInformationSet.size ()); + + return m_nbrApInfoFields.at (nbrApInfoId).tbttInformationSet.at (index).shortSsid; +} + +void +ReducedNeighborReport::SetBssParameters (std::size_t nbrApInfoId, std::size_t index, uint8_t bssParameters) +{ + NS_ASSERT (nbrApInfoId < m_nbrApInfoFields.size ()); + NS_ASSERT (index < m_nbrApInfoFields.at (nbrApInfoId).tbttInformationSet.size ()); + + m_nbrApInfoFields.at (nbrApInfoId).tbttInformationSet.at (index).bssParameters = bssParameters; + + m_nbrApInfoFields.at (nbrApInfoId).hasBssParams = true; +} + +bool +ReducedNeighborReport::HasBssParameters (std::size_t nbrApInfoId) const +{ + NS_ASSERT (nbrApInfoId < m_nbrApInfoFields.size ()); + + return m_nbrApInfoFields.at (nbrApInfoId).hasBssParams; +} + +uint8_t +ReducedNeighborReport::GetBssParameters (std::size_t nbrApInfoId, std::size_t index) const +{ + NS_ASSERT (HasBssParameters (nbrApInfoId)); + NS_ASSERT (index < m_nbrApInfoFields.at (nbrApInfoId).tbttInformationSet.size ()); + + return m_nbrApInfoFields.at (nbrApInfoId).tbttInformationSet.at (index).bssParameters; +} + +void +ReducedNeighborReport::SetPsd20MHz (std::size_t nbrApInfoId, std::size_t index, uint8_t psd20MHz) +{ + NS_ASSERT (nbrApInfoId < m_nbrApInfoFields.size ()); + NS_ASSERT (index < m_nbrApInfoFields.at (nbrApInfoId).tbttInformationSet.size ()); + + m_nbrApInfoFields.at (nbrApInfoId).tbttInformationSet.at (index).psd20MHz = psd20MHz; + + m_nbrApInfoFields.at (nbrApInfoId).has20MHzPsd = true; +} + +bool +ReducedNeighborReport::HasPsd20MHz (std::size_t nbrApInfoId) const +{ + NS_ASSERT (nbrApInfoId < m_nbrApInfoFields.size ()); + + return m_nbrApInfoFields.at (nbrApInfoId).has20MHzPsd; +} + +uint8_t +ReducedNeighborReport::GetPsd20MHz (std::size_t nbrApInfoId, std::size_t index) const +{ + NS_ASSERT (HasPsd20MHz (nbrApInfoId)); + NS_ASSERT (index < m_nbrApInfoFields.at (nbrApInfoId).tbttInformationSet.size ()); + + return m_nbrApInfoFields.at (nbrApInfoId).tbttInformationSet.at (index).psd20MHz; +} + +void +ReducedNeighborReport::SetMldParameters (std::size_t nbrApInfoId, std::size_t index, + uint8_t mldId, uint8_t linkId, uint8_t changeCount) +{ + NS_ASSERT (nbrApInfoId < m_nbrApInfoFields.size ()); + NS_ASSERT (index < m_nbrApInfoFields.at (nbrApInfoId).tbttInformationSet.size ()); + + auto it = std::next (m_nbrApInfoFields.at (nbrApInfoId).tbttInformationSet.begin (), index); + it->mldParameters.mldId = mldId; + it->mldParameters.linkId = (linkId & 0x0f); + it->mldParameters.bssParamsChangeCount = changeCount; + + m_nbrApInfoFields.at (nbrApInfoId).hasMldParams = true; +} + +bool +ReducedNeighborReport::HasMldParameters (std::size_t nbrApInfoId) const +{ + NS_ASSERT (nbrApInfoId < m_nbrApInfoFields.size ()); + + return m_nbrApInfoFields.at (nbrApInfoId).hasMldParams; +} + +uint8_t +ReducedNeighborReport::GetMldId (std::size_t nbrApInfoId, std::size_t index) const +{ + NS_ASSERT (HasMldParameters (nbrApInfoId)); + NS_ASSERT (index < m_nbrApInfoFields.at (nbrApInfoId).tbttInformationSet.size ()); + + return m_nbrApInfoFields.at (nbrApInfoId).tbttInformationSet.at (index).mldParameters.mldId; +} + +uint8_t +ReducedNeighborReport::GetLinkId (std::size_t nbrApInfoId, std::size_t index) const +{ + NS_ASSERT (HasMldParameters (nbrApInfoId)); + NS_ASSERT (index < m_nbrApInfoFields.at (nbrApInfoId).tbttInformationSet.size ()); + + return m_nbrApInfoFields.at (nbrApInfoId).tbttInformationSet.at (index).mldParameters.linkId & 0x0f; +} + +uint8_t +ReducedNeighborReport::GetTbttInformationCount (std::size_t nbrApInfoId) const +{ + NS_ASSERT (nbrApInfoId < m_nbrApInfoFields.size ()); + + return 1 + m_nbrApInfoFields.at (nbrApInfoId).tbttInfoHdr.tbttInfoCount; +} + +uint8_t +ReducedNeighborReport::GetInformationFieldSize () const +{ + uint8_t size = 0; + + for (const auto& neighborApInfo : m_nbrApInfoFields) + { + size += 4; + + size += 1 * neighborApInfo.tbttInformationSet.size (); + + if (neighborApInfo.hasBssid) + { + size += 6 * neighborApInfo.tbttInformationSet.size (); + } + if (neighborApInfo.hasShortSsid) + { + size += 4 * neighborApInfo.tbttInformationSet.size (); + } + if (neighborApInfo.hasBssParams) + { + size += 1 * neighborApInfo.tbttInformationSet.size (); + } + if (neighborApInfo.has20MHzPsd) + { + size += 1 * neighborApInfo.tbttInformationSet.size (); + } + if (neighborApInfo.hasMldParams) + { + size += 3 * neighborApInfo.tbttInformationSet.size (); + } + } + + return size; +} + +void +ReducedNeighborReport::SerializeInformationField (Buffer::Iterator start) const +{ + for (std::size_t id = 0; id < m_nbrApInfoFields.size (); ++ id) + { + WriteTbttInformationLength (id); + } + + for (auto& neighborApInfo : m_nbrApInfoFields) + { + // serialize the TBTT Information Header + uint16_t tbttInfoHdr = 0; + tbttInfoHdr |= neighborApInfo.tbttInfoHdr.type; + tbttInfoHdr |= (neighborApInfo.tbttInfoHdr.filtered << 2); + tbttInfoHdr |= (neighborApInfo.tbttInfoHdr.tbttInfoCount << 4); + tbttInfoHdr |= (neighborApInfo.tbttInfoHdr.tbttInfoLength << 8); + start.WriteHtolsbU16 (tbttInfoHdr); + + start.WriteU8 (neighborApInfo.operatingClass); + start.WriteU8 (neighborApInfo.channelNumber); + + for (const auto& tbttInformation : neighborApInfo.tbttInformationSet) + { + start.WriteU8 (tbttInformation.neighborApTbttOffset); + + if (neighborApInfo.hasBssid) + { + WriteTo (start, tbttInformation.bssid); + } + if (neighborApInfo.hasShortSsid) + { + start.WriteHtolsbU32 (tbttInformation.shortSsid); + } + if (neighborApInfo.hasBssParams) + { + start.WriteU8 (tbttInformation.bssParameters); + } + if (neighborApInfo.has20MHzPsd) + { + start.WriteU8 (tbttInformation.psd20MHz); + } + if (neighborApInfo.hasMldParams) + { + start.WriteU8 (tbttInformation.mldParameters.mldId); + uint16_t other = 0; + other |= (tbttInformation.mldParameters.linkId & 0x0f); + other |= (tbttInformation.mldParameters.bssParamsChangeCount << 4); + start.WriteHtolsbU16 (other); + } + } + } +} + +uint8_t +ReducedNeighborReport::DeserializeInformationField (Buffer::Iterator start, uint8_t length) +{ + Buffer::Iterator i = start; + uint8_t count = 0; + + while (count < length) + { + AddNbrApInfoField (); + + auto tbttInfoHdr = i.ReadLsbtohU16 (); + m_nbrApInfoFields.back ().tbttInfoHdr.type = tbttInfoHdr & 0x0003; + m_nbrApInfoFields.back ().tbttInfoHdr.filtered = (tbttInfoHdr >> 2) & 0x0001; + m_nbrApInfoFields.back ().tbttInfoHdr.tbttInfoCount = (tbttInfoHdr >> 4) & 0x000f; + m_nbrApInfoFields.back ().tbttInfoHdr.tbttInfoLength = (tbttInfoHdr >> 8) & 0x00ff; + + m_nbrApInfoFields.back ().operatingClass = i.ReadU8 (); + m_nbrApInfoFields.back ().channelNumber = i.ReadU8 (); + count += 4; + + std::size_t neighborId = m_nbrApInfoFields.size () - 1; + ReadTbttInformationLength (neighborId); + + for (uint8_t j = 0; j < GetTbttInformationCount (neighborId); j++) + { + AddTbttInformationField (neighborId); + + m_nbrApInfoFields.back ().tbttInformationSet.back ().neighborApTbttOffset = i.ReadU8 (); + count++; + + if (m_nbrApInfoFields.back ().hasBssid) + { + ReadFrom (i, m_nbrApInfoFields.back ().tbttInformationSet.back ().bssid); + count += 6; + } + if (m_nbrApInfoFields.back ().hasShortSsid) + { + m_nbrApInfoFields.back ().tbttInformationSet.back ().shortSsid = i.ReadLsbtohU32 (); + count += 4; + } + if (m_nbrApInfoFields.back ().hasBssParams) + { + m_nbrApInfoFields.back ().tbttInformationSet.back ().bssParameters = i.ReadU8 (); + count += 1; + } + if (m_nbrApInfoFields.back ().has20MHzPsd) + { + m_nbrApInfoFields.back ().tbttInformationSet.back ().psd20MHz = i.ReadU8 (); + count += 1; + } + if (m_nbrApInfoFields.back ().hasMldParams) + { + m_nbrApInfoFields.back ().tbttInformationSet.back ().mldParameters.mldId = i.ReadU8 (); + uint16_t other = i.ReadLsbtohU16 (); + count += 3; + m_nbrApInfoFields.back ().tbttInformationSet.back ().mldParameters.linkId = other & 0x000f; + m_nbrApInfoFields.back ().tbttInformationSet.back ().mldParameters.bssParamsChangeCount = (other >> 4) & 0x00ff; + } + } + } + + return count; +} + +} //namespace ns3 diff --git a/src/wifi/model/reduced-neighbor-report.h b/src/wifi/model/reduced-neighbor-report.h new file mode 100644 index 000000000..fd8dd70cd --- /dev/null +++ b/src/wifi/model/reduced-neighbor-report.h @@ -0,0 +1,328 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2021 Universita' degli Studi di Napoli Federico II + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Stefano Avallone + */ + +#ifndef REDUCED_NEIGHBOR_REPORT_H +#define REDUCED_NEIGHBOR_REPORT_H + +#include "wifi-information-element.h" +#include "ns3/mac48-address.h" +#include + +namespace ns3 { + +class WifiPhyOperatingChannel; + + +/** + * \brief The Reduced Neighbor Report element + * \ingroup wifi + * + * This class knows how to serialise and deserialise the Reduced Neighbor Report element. + */ +class ReducedNeighborReport : public WifiInformationElement +{ +public: + + /** + * MLD Parameters subfield + */ + struct MldParameters + { + uint8_t mldId; //!< MLD ID + uint8_t linkId; //!< Link ID + uint8_t bssParamsChangeCount; //!< BSS Parameters Change Count + }; + + /** + * TBTT Information field + */ + struct TbttInformation + { + uint8_t neighborApTbttOffset {0}; //!< Neighbor AP TBTT Offset + Mac48Address bssid; //!< BSSID (optional) + uint32_t shortSsid {0}; //!< Short SSID (optional) + uint8_t bssParameters {0}; //!< BSS parameters (optional) + uint8_t psd20MHz {0}; //!< 20 MHz PSD (optional) + MldParameters mldParameters {0, 0, 0}; //!< MLD Parameters (optional) + }; + + /** + * TBTT Information Header subfield + */ + struct TbttInformationHeader + { + uint8_t type : 2; //!< TBTT Information Field Type (2 bits) + uint8_t filtered : 1; //!< Filtered Neighbor AP (1 bit) + uint8_t reserved : 1; //!< Reserved (1 bit) + uint8_t tbttInfoCount : 4; //!< TBTT Information Count (4 bits) + uint8_t tbttInfoLength; //!< TBTT Information Length (8 bits) + }; + + /** + * Neighbor AP information field + */ + struct NeighborApInformation + { + mutable TbttInformationHeader tbttInfoHdr {0, 0, 0, 0, 0}; //!< TBTT Information header + uint8_t operatingClass {0}; //!< Operating class + uint8_t channelNumber {0}; //!< Primary channel number + std::vector tbttInformationSet; //!< One or more TBTT Information fields + + bool hasBssid {false}; //!< whether BSSID is present in all TBTT Information fields + bool hasShortSsid {false}; //!< whether Short SSID is present in all TBTT Information fields + bool hasBssParams {false}; //!< whether BSS parameters is present in all TBTT Information fields + bool has20MHzPsd {false}; //!< whether 20 MHz PSD is present in all TBTT Information fields + bool hasMldParams {false}; //!< whether MLD Parameters is present in all TBTT Information fields + }; + + ReducedNeighborReport (); + + // Implementations of pure virtual methods of WifiInformationElement + WifiInformationElementId ElementId () const override; + uint8_t GetInformationFieldSize () const override; + void SerializeInformationField (Buffer::Iterator start) const override; + uint8_t DeserializeInformationField (Buffer::Iterator start, uint8_t length) override; + + /** + * Get the number of Neighbor AP Information fields + * + * \return the number of Neighbor AP Information fields + */ + std::size_t GetNNbrApInfoFields (void) const; + /** + * Add a Neighbor AP Information field + */ + void AddNbrApInfoField (void); + + /** + * Set the Operating Class and the Channel Number fields of the given + * Neighbor AP Information field based on the given operating channel. + * + * \param nbrApInfoId identifier of the given Neighbor AP Information field + * \param channel the PHY operating channel + */ + void SetOperatingChannel (std::size_t nbrApInfoId, const WifiPhyOperatingChannel& channel); + /** + * Get the operating channel coded into the Operating Class and the Channel Number + * fields of the given Neighbor AP Information field. + * + * \param nbrApInfoId identifier of the given Neighbor AP Information field + * \return the PHY operating channel + */ + WifiPhyOperatingChannel GetOperatingChannel (std::size_t nbrApInfoId) const; + + /** + * Get the number of TBTT Information fields included in the TBTT Information Set + * field of the given Neighbor AP Information field + * + * \param nbrApInfoId identifier of the given Neighbor AP Information field + * \return the number of TBTT Information fields + */ + std::size_t GetNTbttInformationFields (std::size_t nbrApInfoId) const; + /** + * Add a TBTT Information fields to the TBTT Information Set field + * of the given Neighbor AP Information field + * + * \param nbrApInfoId identifier of the given Neighbor AP Information field + */ + void AddTbttInformationField (std::size_t nbrApInfoId); + + /** + * Set the BSSID field of the i-th TBTT Information field of the given + * Neighbor AP Information field + * + * \param nbrApInfoId identifier of the given Neighbor AP Information field + * \param index the index of the given TBTT Information field + * \param bssid the BSSID value + */ + void SetBssid (std::size_t nbrApInfoId, std::size_t index, Mac48Address bssid); + /** + * Return true if the BSSID field is present in all the TBTT Information fields + * of the given Neighbor AP Information field. + * + * \param nbrApInfoId identifier of the given Neighbor AP Information field + * \return true if the BSSID field is present + */ + bool HasBssid (std::size_t nbrApInfoId) const; + /** + * Get the BSSID field (must be present) in the i-th TBTT Information field + * of the given Neighbor AP Information field. + * + * \param nbrApInfoId identifier of the given Neighbor AP Information field + * \param index the index of the given TBTT Information field + * \return the BSSID field + */ + Mac48Address GetBssid (std::size_t nbrApInfoId, std::size_t index) const; + + /** + * Set the Short SSID field of the i-th TBTT Information field of the given + * Neighbor AP Information field + * + * \param nbrApInfoId identifier of the given Neighbor AP Information field + * \param index the index of the given TBTT Information field + * \param shortSsid the short SSID value + */ + void SetShortSsid (std::size_t nbrApInfoId, std::size_t index, uint32_t shortSsid); + /** + * Return true if the Short SSID field is present in all the TBTT Information fields + * of the given Neighbor AP Information field. + * + * \param nbrApInfoId identifier of the given Neighbor AP Information field + * \return true if the Short SSID field is present + */ + bool HasShortSsid (std::size_t nbrApInfoId) const; + /** + * Get the Short SSID field (must be present) in the i-th TBTT Information field + * of the given Neighbor AP Information field. + * + * \param nbrApInfoId identifier of the given Neighbor AP Information field + * \param index the index of the given TBTT Information field + * \return the Short SSID field + */ + uint32_t GetShortSsid (std::size_t nbrApInfoId, std::size_t index) const; + + /** + * Set the BSS Parameters field of the i-th TBTT Information field of the given + * Neighbor AP Information field + * + * \param nbrApInfoId identifier of the given Neighbor AP Information field + * \param index the index of the given TBTT Information field + * \param bssParameters the BSS Parameters value + */ + void SetBssParameters (std::size_t nbrApInfoId, std::size_t index, uint8_t bssParameters); + /** + * Return true if the BSS Parameters field is present in all the TBTT Information fields + * of the given Neighbor AP Information field. + * + * \param nbrApInfoId identifier of the given Neighbor AP Information field + * \return true if the BSS Parameters field is present + */ + bool HasBssParameters (std::size_t nbrApInfoId) const; + /** + * Get the BSS Parameters field (must be present) in the i-th TBTT Information field + * of the given Neighbor AP Information field. + * + * \param nbrApInfoId identifier of the given Neighbor AP Information field + * \param index the index of the given TBTT Information field + * \return the BSS Parameters field + */ + uint8_t GetBssParameters (std::size_t nbrApInfoId, std::size_t index) const; + + /** + * Set the 20 MHz PSD field of the i-th TBTT Information field of the given + * Neighbor AP Information field + * + * \param nbrApInfoId identifier of the given Neighbor AP Information field + * \param index the index of the given TBTT Information field + * \param psd20MHz the 20 MHz PSD value + */ + void SetPsd20MHz (std::size_t nbrApInfoId, std::size_t index, uint8_t psd20MHz); + /** + * Return true if the 20 MHz PSD field is present in all the TBTT Information fields + * of the given Neighbor AP Information field. + * + * \param nbrApInfoId identifier of the given Neighbor AP Information field + * \return true if the 20 MHz PSD field is present + */ + bool HasPsd20MHz (std::size_t nbrApInfoId) const; + /** + * Get the 20 MHz PSD field (must be present) in the i-th TBTT Information field + * of the given Neighbor AP Information field. + * + * \param nbrApInfoId identifier of the given Neighbor AP Information field + * \param index the index of the given TBTT Information field + * \return the 20 MHz PSD field + */ + uint8_t GetPsd20MHz (std::size_t nbrApInfoId, std::size_t index) const; + + /** + * Set the MLD Parameters subfield of the i-th TBTT Information field of the given + * Neighbor AP Information field + * + * \param nbrApInfoId identifier of the given Neighbor AP Information field + * \param index the index of the given TBTT Information field + * \param mldId the MLD ID value + * \param linkId the Link ID value + * \param changeSequence the Change Sequence value + */ + void SetMldParameters (std::size_t nbrApInfoId, std::size_t index, + uint8_t mldId, uint8_t linkId, uint8_t changeSequence); + /** + * Return true if the MLD Parameters subfield is present in all the TBTT Information fields + * of the given Neighbor AP Information field. + * + * \param nbrApInfoId identifier of the given Neighbor AP Information field + * \return true if the MLD Parameters subfield is present + */ + bool HasMldParameters (std::size_t nbrApInfoId) const; + /** + * Get the MLD ID value in the MLD Parameters subfield (must be present) in the + * i-th TBTT Information field of the given Neighbor AP Information field. + * + * \param nbrApInfoId identifier of the given Neighbor AP Information field + * \param index the index of the given TBTT Information field + * \return the MLD ID value + */ + uint8_t GetMldId (std::size_t nbrApInfoId, std::size_t index) const; + /** + * Get the Link ID value in the MLD Parameters subfield (must be present) in the + * i-th TBTT Information field of the given Neighbor AP Information field. + * + * \param nbrApInfoId identifier of the given Neighbor AP Information field + * \param index the index of the given TBTT Information field + * \return the Link ID value + */ + uint8_t GetLinkId (std::size_t nbrApInfoId, std::size_t index) const; + + /** + * Get the TBTT Information Count field of the given Neighbor AP Information field. + * + * \param nbrApInfoId identifier of the given Neighbor AP Information field + * \return the TBTT Information Count + */ + uint8_t GetTbttInformationCount (std::size_t nbrApInfoId) const; + +private: + /** + * Set the TBTT Information Length field of the given Neighbor AP Information field + * based on the xxxPresent flags of the NeighborApInformation struct + * + * This method is marked as const because it needs to be called within the + * SerializeInformationField method. In fact, only when serializing this object + * we can set the TBTT Information Length field based on the TBTT Information + * field contents. + * + * \param nbrApInfoId identifier of the given Neighbor AP Information field + */ + void WriteTbttInformationLength (std::size_t nbrApInfoId) const; + /** + * Use the TBTT Information Length field of the given Neighbor AP Information field + * to set the xxxPresent flags of the NeighborApInformation struct + * + * \param nbrApInfoId identifier of the given Neighbor AP Information field + */ + void ReadTbttInformationLength (std::size_t nbrApInfoId); + + std::vector m_nbrApInfoFields; //!< one or more Neighbor AP Information fields +}; + +} //namespace ns3 + +#endif /* REDUCED_NEIGHBOR_REPORT_H */ diff --git a/src/wifi/model/wifi-information-element.h b/src/wifi/model/wifi-information-element.h index cdf0c4bbc..d85aadba0 100644 --- a/src/wifi/model/wifi-information-element.h +++ b/src/wifi/model/wifi-information-element.h @@ -183,7 +183,9 @@ typedef uint8_t WifiInformationElementId; #define IE_AID ((WifiInformationElementId)197) #define IE_QUIET_CHANNEL ((WifiInformationElementId)198) #define IE_OPERATING_MODE_NOTIFICATION ((WifiInformationElementId)199) -// 200 to 220 are reserved +#define IE_UPSIM ((WifiInformationElementId)200) +#define IE_REDUCED_NEIGHBOR_REPORT ((WifiInformationElementId)201) +// TODO Add 202 to 220. See Table 9-92 of 802.11-2020 #define IE_VENDOR_SPECIFIC ((WifiInformationElementId)221) // 222 to 254 are reserved #define IE_EXTENSION ((WifiInformationElementId)255)