Bug 852: Implement IEEE 802.11 Extended Supported Rates information element
This patch adds to the SupportedRates object the ability to serialise an
Extended Supported Rates information element if the number of supported rates
exceeds the 8 that can be carried by the vanilla Supported Rates element.
--- a/src/devices/mesh/dot11s/peer-link-frame.cc Sat Aug 28 20:42:00 2010 +0200
+++ b/src/devices/mesh/dot11s/peer-link-frame.cc Wed Aug 25 09:10:32 2010 +0100
@@ -120,6 +120,7 @@
if ((uint8_t) (WifiActionHeader::PEER_LINK_CLOSE) != m_subtype)
{
size += m_rates.GetSerializedSize ();
+ size += m_rates.extended.GetSerializedSize ();
}
if ((uint8_t) (WifiActionHeader::PEER_LINK_CONFIRM) != m_subtype)
{
@@ -152,6 +153,7 @@
if ((uint8_t) (WifiActionHeader::PEER_LINK_CLOSE) != m_subtype)
{
i = m_rates.Serialize (i);
+ i = m_rates.extended.Serialize (i);
}
if ((uint8_t) (WifiActionHeader::PEER_LINK_CONFIRM) != m_subtype)
{
@@ -192,6 +194,7 @@
if ((uint8_t) (WifiActionHeader::PEER_LINK_CLOSE) != m_subtype)
{
i = m_rates.Deserialize (i);
+ i = m_rates.extended.DeserializeIfPresent (i);
}
if ((uint8_t) (WifiActionHeader::PEER_LINK_CONFIRM) != m_subtype)
{
--- a/src/devices/wifi/mgt-headers.cc Sat Aug 28 20:42:00 2010 +0200
+++ b/src/devices/wifi/mgt-headers.cc Wed Aug 25 09:10:32 2010 +0100
@@ -61,6 +61,7 @@
uint32_t size = 0;
size += m_ssid.GetSerializedSize ();
size += m_rates.GetSerializedSize ();
+ size += m_rates.extended.GetSerializedSize ();
return size;
}
TypeId
@@ -89,6 +90,7 @@
Buffer::Iterator i = start;
i = m_ssid.Serialize (i);
i = m_rates.Serialize (i);
+ i = m_rates.extended.Serialize (i);
}
uint32_t
MgtProbeRequestHeader::Deserialize (Buffer::Iterator start)
@@ -96,6 +98,7 @@
Buffer::Iterator i = start;
i = m_ssid.Deserialize (i);
i = m_rates.Deserialize (i);
+ i = m_rates.extended.DeserializeIfPresent (i);
return i.GetDistanceFrom (start);
}
@@ -170,6 +173,7 @@
size += m_ssid.GetSerializedSize ();
size += m_rates.GetSerializedSize ();
//size += 3; // ds parameter set
+ size += m_rates.extended.GetSerializedSize ();
// xxx
return size;
}
@@ -199,6 +203,7 @@
i = m_ssid.Serialize (i);
i = m_rates.Serialize (i);
//i.WriteU8 (0, 3); // ds parameter set.
+ i = m_rates.extended.Serialize (i);
}
uint32_t
MgtProbeResponseHeader::Deserialize (Buffer::Iterator start)
@@ -211,6 +216,7 @@
i = m_ssid.Deserialize (i);
i = m_rates.Deserialize (i);
//i.Next (3); // ds parameter set
+ i = m_rates.extended.DeserializeIfPresent (i);
return i.GetDistanceFrom (start);
}
@@ -279,6 +285,7 @@
size += 2;
size += m_ssid.GetSerializedSize ();
size += m_rates.GetSerializedSize ();
+ size += m_rates.extended.GetSerializedSize ();
return size;
}
void
@@ -295,6 +302,7 @@
i.WriteHtonU16 (m_listenInterval);
i = m_ssid.Serialize (i);
i = m_rates.Serialize (i);
+ i = m_rates.extended.Serialize (i);
}
uint32_t
MgtAssocRequestHeader::Deserialize (Buffer::Iterator start)
@@ -304,6 +312,7 @@
m_listenInterval = i.ReadNtohU16 ();
i = m_ssid.Deserialize (i);
i = m_rates.Deserialize (i);
+ i = m_rates.extended.DeserializeIfPresent (i);
return i.GetDistanceFrom (start);
}
@@ -362,6 +371,7 @@
size += m_code.GetSerializedSize ();
size += 2; // aid
size += m_rates.GetSerializedSize ();
+ size += m_rates.extended.GetSerializedSize ();
return size;
}
@@ -379,6 +389,7 @@
i = m_code.Serialize (i);
i.WriteHtonU16 (m_aid);
i = m_rates.Serialize (i);
+ i = m_rates.extended.Serialize (i);
}
uint32_t
MgtAssocResponseHeader::Deserialize (Buffer::Iterator start)
@@ -388,6 +399,7 @@
i = m_code.Deserialize (i);
m_aid = i.ReadNtohU16 ();
i = m_rates.Deserialize (i);
+ i = m_rates.extended.DeserializeIfPresent (i);
return i.GetDistanceFrom (start);
}
/**********************************************************
--- a/src/devices/wifi/supported-rates.cc Sat Aug 28 20:42:00 2010 +0200
+++ b/src/devices/wifi/supported-rates.cc Wed Aug 25 09:10:32 2010 +0100
@@ -27,13 +27,13 @@
namespace ns3 {
SupportedRates::SupportedRates ()
- : m_nRates (0)
+ : extended (this), m_nRates (0)
{}
void
SupportedRates::AddSupportedRate (uint32_t bs)
{
- NS_ASSERT (m_nRates < 8);
+ NS_ASSERT (m_nRates < MAX_SUPPORTED_RATES);
if (IsSupportedRate (bs))
{
return;
@@ -108,12 +108,18 @@
uint8_t
SupportedRates::GetInformationFieldSize () const
{
- return m_nRates;
+ // The Supported Rates Information Element contains only the first 8
+ // supported rates - the remainder appear in the Extended Supported
+ // Rates Information Element.
+ return m_nRates > 8 ? 8 : m_nRates;
}
void
SupportedRates::SerializeInformationField (Buffer::Iterator start) const
{
- start.Write (m_rates, m_nRates);
+ // The Supported Rates Information Element contains only the first 8
+ // supported rates - the remainder appear in the Extended Supported
+ // Rates Information Element.
+ start.Write (m_rates, m_nRates > 8 ? 8 : m_nRates);
}
uint8_t
SupportedRates::DeserializeInformationField (Buffer::Iterator start,
@@ -125,6 +131,89 @@
return m_nRates;
}
+ExtendedSupportedRatesIE::ExtendedSupportedRatesIE ()
+{}
+
+ExtendedSupportedRatesIE::ExtendedSupportedRatesIE (SupportedRates *sr)
+{
+ m_supportedRates = sr;
+}
+
+WifiInformationElementId
+ExtendedSupportedRatesIE::ElementId () const
+{
+ return IE_EXTENDED_SUPPORTED_RATES;
+}
+
+uint8_t
+ExtendedSupportedRatesIE::GetInformationFieldSize () const
+{
+ // If there are 8 or fewer rates then we don't need an Extended
+ // Supported Rates IE and so could return zero here, but we're
+ // overriding the GetSerializedSize() method, so if this function is
+ // invoked in that case then it indicates a programming error. Hence
+ // we have an assertion on that condition.
+ NS_ASSERT(m_supportedRates->m_nRates > 8);
+
+ // The number of rates we have beyond the initial 8 is the size of
+ // the information field.
+ return (m_supportedRates->m_nRates - 8);
+}
+
+void
+ExtendedSupportedRatesIE::SerializeInformationField (Buffer::Iterator start) const
+{
+ // If there are 8 or fewer rates then there should be no Extended
+ // Supported Rates Information Element at all so being here would
+ // seemingly indicate a programming error.
+ //
+ // Our overridden version of the Serialize() method should ensure
+ // that this routine is never invoked in that case (by ensuring that
+ // WifiInformationElement::Serialize() is not invoked).
+ NS_ASSERT(m_supportedRates->m_nRates > 8);
+ start.Write (m_supportedRates->m_rates + 8, m_supportedRates->m_nRates - 8);
+}
+
+Buffer::Iterator
+ExtendedSupportedRatesIE::Serialize (Buffer::Iterator start) const
+{
+ // If there are 8 or fewer rates then we don't need an Extended
+ // Supported Rates IE, so we don't serialise anything.
+ if (m_supportedRates->m_nRates <= 8)
+ {
+ return start;
+ }
+
+ // If there are more than 8 rates then we serialise as per normal.
+ return WifiInformationElement::Serialize (start);
+}
+
+uint16_t
+ExtendedSupportedRatesIE::GetSerializedSize () const
+{
+ // If there are 8 or fewer rates then we don't need an Extended
+ // Supported Rates IE, so it's serialised length will be zero.
+ if (m_supportedRates->m_nRates <= 8)
+ {
+ return 0;
+ }
+
+ // Otherwise, the size of it will be the number of supported rates
+ // beyond 8, plus 2 for the Element ID and Length.
+ return WifiInformationElement::GetSerializedSize ();
+}
+
+uint8_t
+ExtendedSupportedRatesIE::DeserializeInformationField (Buffer::Iterator start,
+ uint8_t length)
+{
+ NS_ASSERT (length > 0);
+ NS_ASSERT (m_supportedRates->m_nRates + length <= MAX_SUPPORTED_RATES);
+ start.Read (m_supportedRates->m_rates + m_supportedRates->m_nRates, length);
+ m_supportedRates->m_nRates += length;
+ return length;
+}
+
std::ostream &operator << (std::ostream &os, const SupportedRates &rates)
{
os << "[";
--- a/src/devices/wifi/supported-rates.h Sat Aug 28 20:42:00 2010 +0200
+++ b/src/devices/wifi/supported-rates.h Wed Aug 25 09:10:32 2010 +0100
@@ -27,6 +27,65 @@
namespace ns3 {
+/**
+ * This defines the maximum number of supported rates that a STA is
+ * allowed to have. Currently this number is set for IEEE 802.11b/g
+ * stations which need 2 rates each from Clauses 15 and 18, and then 8
+ * from Clause 19.
+ */
+#define MAX_SUPPORTED_RATES (12)
+
+class SupportedRates;
+
+/**
+ * \brief The Extended Supported Rates Information Element
+ *
+ * This class knows how to serialise and deserialise the Extended
+ * Supported Rates Element that holds (non-HT) rates beyond the 8 that
+ * the original Supported Rates element can carry.
+ *
+ * The \c SupportedRates class still records all the rates, and an
+ * instance of \c ExtendedSupportedRatesIE lies within \c
+ * SupportedRates.
+ */
+class ExtendedSupportedRatesIE : public WifiInformationElement {
+public:
+ ExtendedSupportedRatesIE ();
+ ExtendedSupportedRatesIE (SupportedRates *rates);
+
+ WifiInformationElementId ElementId () const;
+ uint8_t GetInformationFieldSize () const;
+ void SerializeInformationField (Buffer::Iterator start) const;
+ uint8_t DeserializeInformationField (Buffer::Iterator start,
+ uint8_t length);
+
+ /*
+ * This information element is a bit special in that it is only
+ * included if there are more than 8 rates. To support this we
+ * override the Serialize and GetSerializedSize methods of
+ * WifiInformationElement.
+ */
+ Buffer::Iterator Serialize (Buffer::Iterator start) const;
+ uint16_t GetSerializedSize () const;
+private:
+ /**
+ * This member points to the SupportedRates object that contains the
+ * actual rate details. This class is a friend of that, so we have
+ * access to all the private data we need.
+ */
+ SupportedRates *m_supportedRates;
+};
+
+
+/**
+ * \brief The Supported Rates Information Element
+ *
+ * This class knows how to serialise and deserialise the Supported
+ * Rates Element that holds the first 8 (non-HT) supported rates.
+ *
+ * The \c ExtendedSupportedRatesIE class (of which an instance exists
+ * in objects of this class) deals with rates beyond the first 8.
+ */
class SupportedRates : public WifiInformationElement {
public:
SupportedRates ();
@@ -45,9 +104,19 @@
void SerializeInformationField (Buffer::Iterator start) const;
uint8_t DeserializeInformationField (Buffer::Iterator start,
uint8_t length);
+
+ /*
+ * We support the Extended Supported Rates Information Element
+ * through the ExtendedSupportedRatesIE object which is declared
+ * above. We allow this class to be a friend so that it can access
+ * our private data detailing the rates, and create an instance as
+ * extended.
+ */
+ friend class ExtendedSupportedRatesIE;
+ ExtendedSupportedRatesIE extended;
private:
uint8_t m_nRates;
- uint8_t m_rates[8];
+ uint8_t m_rates[MAX_SUPPORTED_RATES];
};
std::ostream &operator << (std::ostream &os, const SupportedRates &rates);