bug 1482: split PeerLinkFrameStart header into different header types, avoiding the need to set the header type before deserializing
authorTom Henderson <tomh@tomh.org>
Mon, 17 Aug 2015 14:29:51 -0700
changeset 11588 5a52126492c1
parent 11587 38e93ba5afa5
child 11589 d3bfef4544ec
bug 1482: split PeerLinkFrameStart header into different header types, avoiding the need to set the header type before deserializing
src/mesh/model/dot11s/peer-link-frame.cc
src/mesh/model/dot11s/peer-link-frame.h
src/mesh/model/dot11s/peer-management-protocol-mac.cc
src/mesh/test/dot11s/dot11s-test-suite.cc
--- a/src/mesh/model/dot11s/peer-link-frame.cc	Mon Aug 17 14:29:32 2015 -0700
+++ b/src/mesh/model/dot11s/peer-link-frame.cc	Mon Aug 17 14:29:51 2015 -0700
@@ -26,20 +26,15 @@
 
 namespace ns3 {
 namespace dot11s {
-NS_OBJECT_ENSURE_REGISTERED (PeerLinkFrameStart);
+NS_OBJECT_ENSURE_REGISTERED (PeerLinkOpenStart);
 
-PeerLinkFrameStart::PeerLinkFrameStart () :
-  m_subtype (255), m_capability (0), m_aid (0), m_rates (SupportedRates ()), m_meshId (),
+PeerLinkOpenStart::PeerLinkOpenStart () :
+  m_subtype ((uint8_t)(WifiActionHeader::PEER_LINK_OPEN)), m_capability (0), m_aid (0), m_rates (SupportedRates ()), m_meshId (),
   m_config (IeConfiguration ())
 {
 }
 void
-PeerLinkFrameStart::SetPlinkFrameSubtype (uint8_t subtype)
-{
-  m_subtype = subtype;
-}
-void
-PeerLinkFrameStart::SetPlinkFrameStart (PeerLinkFrameStart::PlinkFrameStartFields fields)
+PeerLinkOpenStart::SetPlinkOpenStart (PeerLinkOpenStart::PlinkOpenStartFields fields)
 {
   m_subtype = fields.subtype;
   
@@ -68,10 +63,10 @@
       //reasonCode not used here
     }
 }
-PeerLinkFrameStart::PlinkFrameStartFields
-PeerLinkFrameStart::GetFields () const
+PeerLinkOpenStart::PlinkOpenStartFields
+PeerLinkOpenStart::GetFields () const
 {
-  PlinkFrameStartFields retval;
+  PlinkOpenStartFields retval;
   /// \todo protocol version:
   retval.subtype = m_subtype;
   retval.capability = m_capability;
@@ -83,22 +78,22 @@
   return retval;
 }
 TypeId
-PeerLinkFrameStart::GetTypeId ()
+PeerLinkOpenStart::GetTypeId ()
 {
-  static TypeId tid = TypeId ("ns3::dot11s::PeerLinkFrameStart")
+  static TypeId tid = TypeId ("ns3::dot11s::PeerLinkOpenStart")
     .SetParent<Header> ()
     .SetGroupName ("Mesh")
-    .AddConstructor<PeerLinkFrameStart> ()
+    .AddConstructor<PeerLinkOpenStart> ()
   ;
   return tid;
 }
 TypeId
-PeerLinkFrameStart::GetInstanceTypeId () const
+PeerLinkOpenStart::GetInstanceTypeId () const
 {
   return GetTypeId ();
 }
 void
-PeerLinkFrameStart::Print (std::ostream &os) const
+PeerLinkOpenStart::Print (std::ostream &os) const
 {
   os << "subtype = " << (uint16_t) m_subtype << std::endl << "capability = " << m_capability << std::endl << "laid = "
      << (uint16_t) m_aid << std::endl << "rates = " << m_rates << std::endl << "meshId = ";
@@ -108,7 +103,7 @@
   os << std::endl << "reason code = " << m_reasonCode;
 }
 uint32_t
-PeerLinkFrameStart::GetSerializedSize () const
+PeerLinkOpenStart::GetSerializedSize () const
 {
   uint32_t size =0; //Peering protocol
   NS_ASSERT (m_subtype < 4);
@@ -140,7 +135,7 @@
   return size;
 }
 void
-PeerLinkFrameStart::Serialize (Buffer::Iterator start) const
+PeerLinkOpenStart::Serialize (Buffer::Iterator start) const
 {
   Buffer::Iterator i = start;
   NS_ASSERT (m_subtype < 4);
@@ -172,7 +167,7 @@
     }
 }
 uint32_t
-PeerLinkFrameStart::Deserialize (Buffer::Iterator start)
+PeerLinkOpenStart::Deserialize (Buffer::Iterator start)
 {
   Buffer::Iterator i = start;
   NS_ASSERT (m_subtype < 4);
@@ -219,7 +214,395 @@
   return i.GetDistanceFrom (start);
 }
 bool
-operator== (const PeerLinkFrameStart & a, const PeerLinkFrameStart & b)
+operator== (const PeerLinkOpenStart & a, const PeerLinkOpenStart & b)
+{
+  return ((a.m_subtype == b.m_subtype) && (a.m_capability == b.m_capability) && (a.m_aid == b.m_aid)
+          && (a.m_meshId.IsEqual (b.m_meshId)) && (a.m_config == b.m_config));
+  
+}
+NS_OBJECT_ENSURE_REGISTERED (PeerLinkCloseStart);
+
+PeerLinkCloseStart::PeerLinkCloseStart () :
+  m_subtype ((uint8_t)(WifiActionHeader::PEER_LINK_CLOSE)), m_capability (0), m_aid (0), m_rates (SupportedRates ()), m_meshId (),
+  m_config (IeConfiguration ())
+{
+}
+void
+PeerLinkCloseStart::SetPlinkCloseStart (PeerLinkCloseStart::PlinkCloseStartFields fields)
+{
+  m_subtype = fields.subtype;
+  
+  if (m_subtype != (uint8_t)(WifiActionHeader::PEER_LINK_CLOSE))
+    {
+      m_capability = fields.capability;
+    }
+  if (m_subtype == (uint8_t)(WifiActionHeader::PEER_LINK_CONFIRM))
+    {
+      m_aid = fields.aid;
+    }
+  if (m_subtype != (uint8_t)(WifiActionHeader::PEER_LINK_CLOSE))
+    {
+      m_rates = fields.rates;
+    }
+  if (m_subtype != (uint8_t)(WifiActionHeader::PEER_LINK_CONFIRM))
+    {
+      m_meshId = fields.meshId;
+    }
+  if (m_subtype != (uint8_t)(WifiActionHeader::PEER_LINK_CLOSE))
+    {
+      m_config = fields.config;
+    }
+  else
+    {
+      //reasonCode not used here
+    }
+}
+PeerLinkCloseStart::PlinkCloseStartFields
+PeerLinkCloseStart::GetFields () const
+{
+  PlinkCloseStartFields retval;
+  /// \todo protocol version:
+  retval.subtype = m_subtype;
+  retval.capability = m_capability;
+  retval.aid = m_aid;
+  retval.rates = m_rates;
+  retval.meshId = m_meshId;
+  retval.config = m_config;
+  
+  return retval;
+}
+TypeId
+PeerLinkCloseStart::GetTypeId ()
+{
+  static TypeId tid = TypeId ("ns3::dot11s::PeerLinkCloseStart")
+    .SetParent<Header> ()
+    .SetGroupName ("Mesh")
+    .AddConstructor<PeerLinkCloseStart> ()
+  ;
+  return tid;
+}
+TypeId
+PeerLinkCloseStart::GetInstanceTypeId () const
+{
+  return GetTypeId ();
+}
+void
+PeerLinkCloseStart::Print (std::ostream &os) const
+{
+  os << "subtype = " << (uint16_t) m_subtype << std::endl << "capability = " << m_capability << std::endl << "laid = "
+     << (uint16_t) m_aid << std::endl << "rates = " << m_rates << std::endl << "meshId = ";
+  m_meshId.Print (os);
+  os << std::endl << "configuration = ";
+  m_config.Print (os);
+  os << std::endl << "reason code = " << m_reasonCode;
+}
+uint32_t
+PeerLinkCloseStart::GetSerializedSize () const
+{
+  uint32_t size =0; //Peering protocol
+  NS_ASSERT (m_subtype < 4);
+  if ((uint8_t)(WifiActionHeader::PEER_LINK_CLOSE) != m_subtype)
+    {
+      size += 2; //capability
+    }
+  if ((uint8_t)(WifiActionHeader::PEER_LINK_CONFIRM) == m_subtype)
+    {
+      size += 2; //AID of remote peer
+    }
+  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)
+    {
+      size += m_meshId.GetInformationFieldSize () + 2;
+    }
+  if ((uint8_t)(WifiActionHeader::PEER_LINK_CLOSE) != m_subtype)
+    {
+      size += m_config.GetInformationFieldSize () + 2;
+    }
+  else
+    {
+      //reasonCode not used here
+    }
+  return size;
+}
+void
+PeerLinkCloseStart::Serialize (Buffer::Iterator start) const
+{
+  Buffer::Iterator i = start;
+  NS_ASSERT (m_subtype < 4);
+  
+  if ((uint8_t)(WifiActionHeader::PEER_LINK_CLOSE) != m_subtype)
+    {
+      i.WriteHtolsbU16 (m_capability);
+    }
+  if ((uint8_t)(WifiActionHeader::PEER_LINK_CONFIRM) == m_subtype)
+    {
+      i.WriteHtolsbU16 (m_aid);
+    }
+  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)
+    {
+      i = m_meshId.Serialize (i);
+    }
+  if ((uint8_t)(WifiActionHeader::PEER_LINK_CLOSE) != m_subtype)
+    {
+      i = m_config.Serialize (i);
+    }
+  else
+    {
+      //reasonCode not used here
+    }
+}
+uint32_t
+PeerLinkCloseStart::Deserialize (Buffer::Iterator start)
+{
+  Buffer::Iterator i = start;
+  NS_ASSERT (m_subtype < 4);
+  
+  if ((uint8_t)(WifiActionHeader::PEER_LINK_CLOSE) != m_subtype)
+    {
+      m_capability = i.ReadLsbtohU16 ();
+    }
+  if ((uint8_t)(WifiActionHeader::PEER_LINK_CONFIRM) == m_subtype)
+    {
+      m_aid = i.ReadLsbtohU16 ();
+    }
+  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)
+    {
+      uint8_t id = i.ReadU8 ();
+      uint8_t length = i.ReadU8 ();
+      m_meshId.DeserializeInformationField (i, length);
+      if ((m_meshId.ElementId () != (WifiInformationElementId) id) || (m_meshId.GetInformationFieldSize () != length))
+        {
+          NS_FATAL_ERROR ("Broken frame: Element ID does not match IE itself!");
+        }
+      i.Next (m_meshId.GetInformationFieldSize ());
+    }
+  if ((uint8_t)(WifiActionHeader::PEER_LINK_CLOSE) != m_subtype)
+    {
+      uint8_t id = i.ReadU8 ();
+      uint8_t length = i.ReadU8 ();
+      m_config.DeserializeInformationField (i, length);
+      if ((m_config.ElementId () != (WifiInformationElementId) id) || (m_config.GetInformationFieldSize () != length))
+        {
+          NS_FATAL_ERROR ("Broken frame: Element ID does not match IE itself!");
+        }
+      i.Next (m_config.GetInformationFieldSize ());
+    }
+  else
+    {
+       //reasonCode not used here
+    }
+  return i.GetDistanceFrom (start);
+}
+bool
+operator== (const PeerLinkCloseStart & a, const PeerLinkCloseStart & b)
+{
+  return ((a.m_subtype == b.m_subtype) && (a.m_capability == b.m_capability) && (a.m_aid == b.m_aid)
+          && (a.m_meshId.IsEqual (b.m_meshId)) && (a.m_config == b.m_config));
+  
+}
+NS_OBJECT_ENSURE_REGISTERED (PeerLinkConfirmStart);
+
+PeerLinkConfirmStart::PeerLinkConfirmStart () :
+  m_subtype ((uint8_t)(WifiActionHeader::PEER_LINK_CONFIRM)), m_capability (0), m_aid (0), m_rates (SupportedRates ()), m_meshId (),
+  m_config (IeConfiguration ())
+{
+}
+void
+PeerLinkConfirmStart::SetPlinkConfirmStart (PeerLinkConfirmStart::PlinkConfirmStartFields fields)
+{
+  m_subtype = fields.subtype;
+  
+  if (m_subtype != (uint8_t)(WifiActionHeader::PEER_LINK_CLOSE))
+    {
+      m_capability = fields.capability;
+    }
+  if (m_subtype == (uint8_t)(WifiActionHeader::PEER_LINK_CONFIRM))
+    {
+      m_aid = fields.aid;
+    }
+  if (m_subtype != (uint8_t)(WifiActionHeader::PEER_LINK_CLOSE))
+    {
+      m_rates = fields.rates;
+    }
+  if (m_subtype != (uint8_t)(WifiActionHeader::PEER_LINK_CONFIRM))
+    {
+      m_meshId = fields.meshId;
+    }
+  if (m_subtype != (uint8_t)(WifiActionHeader::PEER_LINK_CLOSE))
+    {
+      m_config = fields.config;
+    }
+  else
+    {
+      //reasonCode not used here
+    }
+}
+PeerLinkConfirmStart::PlinkConfirmStartFields
+PeerLinkConfirmStart::GetFields () const
+{
+  PlinkConfirmStartFields retval;
+  /// \todo protocol version:
+  retval.subtype = m_subtype;
+  retval.capability = m_capability;
+  retval.aid = m_aid;
+  retval.rates = m_rates;
+  retval.meshId = m_meshId;
+  retval.config = m_config;
+  
+  return retval;
+}
+TypeId
+PeerLinkConfirmStart::GetTypeId ()
+{
+  static TypeId tid = TypeId ("ns3::dot11s::PeerLinkConfirmStart")
+    .SetParent<Header> ()
+    .SetGroupName ("Mesh")
+    .AddConstructor<PeerLinkConfirmStart> ()
+  ;
+  return tid;
+}
+TypeId
+PeerLinkConfirmStart::GetInstanceTypeId () const
+{
+  return GetTypeId ();
+}
+void
+PeerLinkConfirmStart::Print (std::ostream &os) const
+{
+  os << "subtype = " << (uint16_t) m_subtype << std::endl << "capability = " << m_capability << std::endl << "laid = "
+     << (uint16_t) m_aid << std::endl << "rates = " << m_rates << std::endl << "meshId = ";
+  m_meshId.Print (os);
+  os << std::endl << "configuration = ";
+  m_config.Print (os);
+  os << std::endl << "reason code = " << m_reasonCode;
+}
+uint32_t
+PeerLinkConfirmStart::GetSerializedSize () const
+{
+  uint32_t size =0; //Peering protocol
+  NS_ASSERT (m_subtype < 4);
+  if ((uint8_t)(WifiActionHeader::PEER_LINK_CLOSE) != m_subtype)
+    {
+      size += 2; //capability
+    }
+  if ((uint8_t)(WifiActionHeader::PEER_LINK_CONFIRM) == m_subtype)
+    {
+      size += 2; //AID of remote peer
+    }
+  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)
+    {
+      size += m_meshId.GetInformationFieldSize () + 2;
+    }
+  if ((uint8_t)(WifiActionHeader::PEER_LINK_CLOSE) != m_subtype)
+    {
+      size += m_config.GetInformationFieldSize () + 2;
+    }
+  else
+    {
+      //reasonCode not used here
+    }
+  return size;
+}
+void
+PeerLinkConfirmStart::Serialize (Buffer::Iterator start) const
+{
+  Buffer::Iterator i = start;
+  NS_ASSERT (m_subtype < 4);
+  
+  if ((uint8_t)(WifiActionHeader::PEER_LINK_CLOSE) != m_subtype)
+    {
+      i.WriteHtolsbU16 (m_capability);
+    }
+  if ((uint8_t)(WifiActionHeader::PEER_LINK_CONFIRM) == m_subtype)
+    {
+      i.WriteHtolsbU16 (m_aid);
+    }
+  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)
+    {
+      i = m_meshId.Serialize (i);
+    }
+  if ((uint8_t)(WifiActionHeader::PEER_LINK_CLOSE) != m_subtype)
+    {
+      i = m_config.Serialize (i);
+    }
+  else
+    {
+      //reasonCode not used here
+    }
+}
+uint32_t
+PeerLinkConfirmStart::Deserialize (Buffer::Iterator start)
+{
+  Buffer::Iterator i = start;
+  NS_ASSERT (m_subtype < 4);
+  
+  if ((uint8_t)(WifiActionHeader::PEER_LINK_CLOSE) != m_subtype)
+    {
+      m_capability = i.ReadLsbtohU16 ();
+    }
+  if ((uint8_t)(WifiActionHeader::PEER_LINK_CONFIRM) == m_subtype)
+    {
+      m_aid = i.ReadLsbtohU16 ();
+    }
+  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)
+    {
+      uint8_t id = i.ReadU8 ();
+      uint8_t length = i.ReadU8 ();
+      m_meshId.DeserializeInformationField (i, length);
+      if ((m_meshId.ElementId () != (WifiInformationElementId) id) || (m_meshId.GetInformationFieldSize () != length))
+        {
+          NS_FATAL_ERROR ("Broken frame: Element ID does not match IE itself!");
+        }
+      i.Next (m_meshId.GetInformationFieldSize ());
+    }
+  if ((uint8_t)(WifiActionHeader::PEER_LINK_CLOSE) != m_subtype)
+    {
+      uint8_t id = i.ReadU8 ();
+      uint8_t length = i.ReadU8 ();
+      m_config.DeserializeInformationField (i, length);
+      if ((m_config.ElementId () != (WifiInformationElementId) id) || (m_config.GetInformationFieldSize () != length))
+        {
+          NS_FATAL_ERROR ("Broken frame: Element ID does not match IE itself!");
+        }
+      i.Next (m_config.GetInformationFieldSize ());
+    }
+  else
+    {
+       //reasonCode not used here
+    }
+  return i.GetDistanceFrom (start);
+}
+bool
+operator== (const PeerLinkConfirmStart & a, const PeerLinkConfirmStart & b)
 {
   return ((a.m_subtype == b.m_subtype) && (a.m_capability == b.m_capability) && (a.m_aid == b.m_aid)
           && (a.m_meshId.IsEqual (b.m_meshId)) && (a.m_config == b.m_config));
--- a/src/mesh/model/dot11s/peer-link-frame.h	Mon Aug 17 14:29:32 2015 -0700
+++ b/src/mesh/model/dot11s/peer-link-frame.h	Mon Aug 17 14:29:51 2015 -0700
@@ -28,13 +28,12 @@
 #include "ie-dot11s-id.h"
 namespace ns3
 {
-class MeshWifiInterfaceMac;
 namespace dot11s
 {
 /**
  * \ingroup dot11s
  *
- * \brief 802.11s Peer link management frame
+ * \brief 802.11s Peer link open management frame
  * 
  * Peer link management frame included the following (see chapters 7.4.12.1-7.4.12.3 of 802.11s):
  * - Subtype field
@@ -42,12 +41,12 @@
  * - Supported rates
  * - Mesh ID of mesh
  */
-class PeerLinkFrameStart : public Header
+class PeerLinkOpenStart : public Header
 {
 public:
-  PeerLinkFrameStart ();
+  PeerLinkOpenStart ();
   ///\brief fields:
-  struct PlinkFrameStartFields
+  struct PlinkOpenStartFields
   {
     uint8_t subtype;
     IePeeringProtocol protocol; //Peering protocol version - in all subtypes - 3 octets
@@ -58,11 +57,8 @@
     IeConfiguration config;     //open and confirm
     uint16_t reasonCode;        //close only
   };
-  ///\attention: must be set before deserialize, before only multihop
-  //action header knows about subtype
-  void SetPlinkFrameSubtype (uint8_t subtype);
-  void SetPlinkFrameStart (PlinkFrameStartFields);
-  PlinkFrameStartFields GetFields () const;
+  void SetPlinkOpenStart (PlinkOpenStartFields);
+  PlinkOpenStartFields GetFields () const;
 
   // Inherited from header:
   static  TypeId   GetTypeId ();
@@ -82,13 +78,126 @@
   IeConfiguration m_config;
   uint16_t m_reasonCode;
 
-  friend bool operator== (const PeerLinkFrameStart & a, const PeerLinkFrameStart & b);
+  friend bool operator== (const PeerLinkOpenStart & a, const PeerLinkOpenStart & b);
 
-  PeerLinkFrameStart& operator= (const PeerLinkFrameStart &);
-  PeerLinkFrameStart (const PeerLinkFrameStart &);
+  PeerLinkOpenStart& operator= (const PeerLinkOpenStart &);
+  PeerLinkOpenStart (const PeerLinkOpenStart &);
 
 };
-bool operator== (const PeerLinkFrameStart & a, const PeerLinkFrameStart & b);
+
+bool operator== (const PeerLinkOpenStart & a, const PeerLinkOpenStart & b);
+
+/**
+ * \ingroup dot11s
+ *
+ * \brief 802.11s Peer link close management frame
+ * 
+ * Peer link management frame included the following (see chapters 7.4.12.1-7.4.12.3 of 802.11s):
+ * - Subtype field
+ * - Association ID field
+ * - Supported rates
+ * - Mesh ID of mesh
+ */
+class PeerLinkCloseStart : public Header
+{
+public:
+  PeerLinkCloseStart ();
+  ///\brief fields:
+  struct PlinkCloseStartFields
+  {
+    uint8_t subtype;
+    IePeeringProtocol protocol; //Peering protocol version - in all subtypes - 3 octets
+    uint16_t capability;        //open and confirm
+    uint16_t aid;               //confirm only
+    SupportedRates rates;       //open and confirm
+    IeMeshId meshId;            //open and close
+    IeConfiguration config;     //open and confirm
+    uint16_t reasonCode;        //close only
+  };
+  void SetPlinkCloseStart (PlinkCloseStartFields);
+  PlinkCloseStartFields GetFields () const;
+
+  // Inherited from header:
+  static  TypeId   GetTypeId ();
+  virtual TypeId   GetInstanceTypeId () const;
+  virtual void     Print (std::ostream &os) const;
+  virtual uint32_t GetSerializedSize () const;
+  virtual void     Serialize (Buffer::Iterator start) const;
+  virtual uint32_t Deserialize (Buffer::Iterator start);
+
+private:
+  uint8_t m_subtype;
+  IePeeringProtocol m_protocol;
+  uint16_t m_capability;
+  uint16_t m_aid;
+  SupportedRates m_rates;
+  IeMeshId m_meshId;
+  IeConfiguration m_config;
+  uint16_t m_reasonCode;
+
+  friend bool operator== (const PeerLinkCloseStart & a, const PeerLinkCloseStart & b);
+
+  PeerLinkCloseStart& operator= (const PeerLinkCloseStart &);
+  PeerLinkCloseStart (const PeerLinkCloseStart &);
+
+};
+bool operator== (const PeerLinkCloseStart & a, const PeerLinkCloseStart & b);
+
+/**
+ * \ingroup dot11s
+ *
+ * \brief 802.11s Peer link confirm management frame
+ * 
+ * Peer link management frame included the following (see chapters 7.4.12.1-7.4.12.3 of 802.11s):
+ * - Subtype field
+ * - Association ID field
+ * - Supported rates
+ * - Mesh ID of mesh
+ */
+class PeerLinkConfirmStart : public Header
+{
+public:
+  PeerLinkConfirmStart ();
+  ///\brief fields:
+  struct PlinkConfirmStartFields
+  {
+    uint8_t subtype;
+    IePeeringProtocol protocol; //Peering protocol version - in all subtypes - 3 octets
+    uint16_t capability;        //open and confirm
+    uint16_t aid;               //confirm only
+    SupportedRates rates;       //open and confirm
+    IeMeshId meshId;            //open and close
+    IeConfiguration config;     //open and confirm
+    uint16_t reasonCode;        //close only
+  };
+  void SetPlinkConfirmStart (PlinkConfirmStartFields);
+  PlinkConfirmStartFields GetFields () const;
+
+  // Inherited from header:
+  static  TypeId   GetTypeId ();
+  virtual TypeId   GetInstanceTypeId () const;
+  virtual void     Print (std::ostream &os) const;
+  virtual uint32_t GetSerializedSize () const;
+  virtual void     Serialize (Buffer::Iterator start) const;
+  virtual uint32_t Deserialize (Buffer::Iterator start);
+
+private:
+  uint8_t m_subtype;
+  IePeeringProtocol m_protocol;
+  uint16_t m_capability;
+  uint16_t m_aid;
+  SupportedRates m_rates;
+  IeMeshId m_meshId;
+  IeConfiguration m_config;
+  uint16_t m_reasonCode;
+
+  friend bool operator== (const PeerLinkConfirmStart & a, const PeerLinkConfirmStart & b);
+
+  PeerLinkConfirmStart& operator= (const PeerLinkConfirmStart &);
+  PeerLinkConfirmStart (const PeerLinkConfirmStart &);
+
+};
+bool operator== (const PeerLinkConfirmStart & a, const PeerLinkConfirmStart & b);
 } // namespace dot11s
 } // namespace ns3
 #endif
--- a/src/mesh/model/dot11s/peer-management-protocol-mac.cc	Mon Aug 17 14:29:32 2015 -0700
+++ b/src/mesh/model/dot11s/peer-management-protocol-mac.cc	Mon Aug 17 14:29:51 2015 -0700
@@ -82,6 +82,8 @@
       // Beacon shall not be dropped. May be needed to another plugins
       return true;
     }
+  uint16_t aid;
+  IeConfiguration config;
   if (header.IsAction ())
     {
       WifiActionHeader actionHdr;
@@ -96,28 +98,67 @@
       m_stats.rxMgtBytes += packet->GetSize ();
       Mac48Address peerAddress = header.GetAddr2 ();
       Mac48Address peerMpAddress = header.GetAddr3 ();
-      PeerLinkFrameStart::PlinkFrameStartFields fields;
-      {
-        PeerLinkFrameStart peerFrame;
-        peerFrame.SetPlinkFrameSubtype ((uint8_t) actionValue.selfProtectedAction);
-        packet->RemoveHeader (peerFrame);
-        fields = peerFrame.GetFields ();
-        NS_ASSERT (fields.subtype == actionValue.selfProtectedAction); 
-      }
-      if ((actionValue.selfProtectedAction != WifiActionHeader::PEER_LINK_CLOSE) && !(m_parent->CheckSupportedRates (fields.rates))) 
+      if (actionValue.selfProtectedAction == WifiActionHeader::PEER_LINK_OPEN)
+        {
+          PeerLinkOpenStart::PlinkOpenStartFields fields;
+          PeerLinkOpenStart peerFrame;
+          packet->RemoveHeader (peerFrame);
+          fields = peerFrame.GetFields ();
+          NS_ASSERT (fields.subtype == actionValue.selfProtectedAction); 
+          if (!fields.meshId.IsEqual ( *(m_protocol->GetMeshId ())))
+            {
+              m_protocol->ConfigurationMismatch (m_ifIndex, peerAddress);
+              // Broken peer link frame - drop it
+              m_stats.brokenMgt++;
+              return false;
+            }
+          if (!(m_parent->CheckSupportedRates (fields.rates)))
+            {
+              m_protocol->ConfigurationMismatch (m_ifIndex, peerAddress);
+              // Broken peer link frame - drop it
+              m_stats.brokenMgt++;
+              return false;
+            }
+          aid = fields.aid;
+          config = fields.config;
+        }
+      else if (actionValue.selfProtectedAction == WifiActionHeader::PEER_LINK_CONFIRM)
         {
-          m_protocol->ConfigurationMismatch (m_ifIndex, peerAddress);
-          // Broken peer link frame - drop it
-          m_stats.brokenMgt++;
-          return false;
+          PeerLinkConfirmStart::PlinkConfirmStartFields fields;
+          PeerLinkConfirmStart peerFrame;
+          packet->RemoveHeader (peerFrame);
+          fields = peerFrame.GetFields ();
+          NS_ASSERT (fields.subtype == actionValue.selfProtectedAction); 
+          if (!(m_parent->CheckSupportedRates (fields.rates)))
+            {
+              m_protocol->ConfigurationMismatch (m_ifIndex, peerAddress);
+              // Broken peer link frame - drop it
+              m_stats.brokenMgt++;
+              return false;
+            }
+          aid = fields.aid;
+          config = fields.config;
         }
-     if ((actionValue.selfProtectedAction != WifiActionHeader::PEER_LINK_CONFIRM) && !fields.meshId.IsEqual (
-            *(m_protocol->GetMeshId ())))
+      else if (actionValue.selfProtectedAction == WifiActionHeader::PEER_LINK_CLOSE)
         {
-          m_protocol->ConfigurationMismatch (m_ifIndex, peerAddress);
-          // Broken peer link frame - drop it
-          m_stats.brokenMgt++;
-          return false;
+          PeerLinkCloseStart::PlinkCloseStartFields fields;
+          PeerLinkCloseStart peerFrame;
+          packet->RemoveHeader (peerFrame);
+          fields = peerFrame.GetFields ();
+          NS_ASSERT (fields.subtype == actionValue.selfProtectedAction); 
+          if (!fields.meshId.IsEqual ( *(m_protocol->GetMeshId ())))
+            {
+              m_protocol->ConfigurationMismatch (m_ifIndex, peerAddress);
+              // Broken peer link frame - drop it
+              m_stats.brokenMgt++;
+              return false;
+            }
+          aid = fields.aid;
+          config = fields.config;
+        }
+      else
+        {
+          NS_FATAL_ERROR ("Unknown subtype" << actionValue.selfProtectedAction);
         }
       Ptr<IePeerManagement> peerElement;
       //Peer Management element is the last element in this frame - so, we can use MeshInformationElementVector
@@ -143,8 +184,7 @@
            NS_ASSERT (actionValue.selfProtectedAction == WifiActionHeader::PEER_LINK_CLOSE); 
         }
       //Deliver Peer link management frame to protocol:
-      m_protocol->ReceivePeerLinkFrame (m_ifIndex, peerAddress, peerMpAddress, fields.aid, *peerElement,
-                                        fields.config);
+      m_protocol->ReceivePeerLinkFrame (m_ifIndex, peerAddress, peerMpAddress, aid, *peerElement, config);
       // if we can handle a frame - drop it
       return false;
     }
@@ -202,44 +242,64 @@
   MeshInformationElementVector elements;
   elements.AddInformationElement (Ptr<IePeerManagement> (&peerElement));
   packet->AddHeader (elements);
-  PeerLinkFrameStart::PlinkFrameStartFields fields;
-  fields.rates = m_parent->GetSupportedRates ();
-  fields.capability = 0;
-  fields.meshId = *(m_protocol->GetMeshId ());
-  fields.config = meshConfig;
-  PeerLinkFrameStart plinkFrame;
   //Create an 802.11 frame header:
   //Send management frame to MAC:
-  WifiActionHeader actionHdr;
   if (peerElement.SubtypeIsOpen ())
     {
+      PeerLinkOpenStart::PlinkOpenStartFields fields;
+      fields.rates = m_parent->GetSupportedRates ();
+      fields.capability = 0;
+      fields.meshId = *(m_protocol->GetMeshId ());
+      fields.config = meshConfig;
+      PeerLinkOpenStart plinkOpen;
+      WifiActionHeader actionHdr;
       m_stats.txOpen++;
       WifiActionHeader::ActionValue action;
       action.selfProtectedAction = WifiActionHeader::PEER_LINK_OPEN;
       fields.subtype = WifiActionHeader::PEER_LINK_OPEN;
       actionHdr.SetAction (WifiActionHeader::SELF_PROTECTED, action); 
+      plinkOpen.SetPlinkOpenStart (fields);
+      packet->AddHeader (plinkOpen);
+      packet->AddHeader (actionHdr);
     }
   if (peerElement.SubtypeIsConfirm ())
     {
+      PeerLinkConfirmStart::PlinkConfirmStartFields fields;
+      fields.rates = m_parent->GetSupportedRates ();
+      fields.capability = 0;
+      fields.meshId = *(m_protocol->GetMeshId ());
+      fields.config = meshConfig;
+      PeerLinkConfirmStart plinkConfirm;
+      WifiActionHeader actionHdr;
       m_stats.txConfirm++;
       WifiActionHeader::ActionValue action;
-       action.selfProtectedAction = WifiActionHeader::PEER_LINK_CONFIRM; 
+      action.selfProtectedAction = WifiActionHeader::PEER_LINK_CONFIRM; 
       fields.aid = aid;
       fields.subtype = WifiActionHeader::PEER_LINK_CONFIRM;
       actionHdr.SetAction (WifiActionHeader::SELF_PROTECTED, action); 
+      plinkConfirm.SetPlinkConfirmStart (fields);
+      packet->AddHeader (plinkConfirm);
+      packet->AddHeader (actionHdr);
     }
   if (peerElement.SubtypeIsClose ())
     {
+      PeerLinkCloseStart::PlinkCloseStartFields fields;
+      fields.rates = m_parent->GetSupportedRates ();
+      fields.capability = 0;
+      fields.meshId = *(m_protocol->GetMeshId ());
+      fields.config = meshConfig;
+      PeerLinkCloseStart plinkClose;
+      WifiActionHeader actionHdr;
       m_stats.txClose++;
       WifiActionHeader::ActionValue action;
       action.selfProtectedAction = WifiActionHeader::PEER_LINK_CLOSE; 
       fields.subtype = WifiActionHeader::PEER_LINK_CLOSE;
       fields.reasonCode = peerElement.GetReasonCode ();
       actionHdr.SetAction (WifiActionHeader::SELF_PROTECTED, action); 
+      plinkClose.SetPlinkCloseStart (fields);
+      packet->AddHeader (plinkClose);
+      packet->AddHeader (actionHdr);
     }
-  plinkFrame.SetPlinkFrameStart (fields);
-  packet->AddHeader (plinkFrame);
-  packet->AddHeader (actionHdr);
   m_stats.txMgt++;
   m_stats.txMgtBytes += packet->GetSize ();
   // Wifi Mac header:
--- a/src/mesh/test/dot11s/dot11s-test-suite.cc	Mon Aug 17 14:29:32 2015 -0700
+++ b/src/mesh/test/dot11s/dot11s-test-suite.cc	Mon Aug 17 14:29:51 2015 -0700
@@ -216,50 +216,47 @@
 PeerLinkFrameStartTest::DoRun ()
 {
   {
-    PeerLinkFrameStart a;
-    PeerLinkFrameStart::PlinkFrameStartFields fields;
+    PeerLinkOpenStart a;
+    PeerLinkOpenStart::PlinkOpenStartFields fields;
     fields.subtype = (uint8_t)(WifiActionHeader::PEER_LINK_OPEN);
     fields.capability = 0;
     fields.aid = 101;
     fields.reasonCode = 12;
     fields.meshId = IeMeshId ("qwertyuiop");
-    a.SetPlinkFrameStart (fields);
+    a.SetPlinkOpenStart (fields);
     Ptr<Packet> packet = Create<Packet> ();
     packet->AddHeader (a);
-    PeerLinkFrameStart b;
-    b.SetPlinkFrameSubtype ((uint8_t)(WifiActionHeader::PEER_LINK_OPEN));
+    PeerLinkOpenStart b;
     packet->RemoveHeader (b);
     NS_TEST_EXPECT_MSG_EQ (a, b, "PEER_LINK_OPEN works");
   }
   {
-    PeerLinkFrameStart a;
-    PeerLinkFrameStart::PlinkFrameStartFields fields;
+    PeerLinkConfirmStart a;
+    PeerLinkConfirmStart::PlinkConfirmStartFields fields;
     fields.subtype = (uint8_t)(WifiActionHeader::PEER_LINK_CONFIRM);
     fields.capability = 0;
     fields.aid = 1234;
     fields.reasonCode = 12;
     fields.meshId = IeMeshId ("qwerty");
-    a.SetPlinkFrameStart (fields);
+    a.SetPlinkConfirmStart (fields);
     Ptr<Packet> packet = Create<Packet> ();
     packet->AddHeader (a);
-    PeerLinkFrameStart b;
-    b.SetPlinkFrameSubtype ((uint8_t)(WifiActionHeader::PEER_LINK_CONFIRM));
+    PeerLinkConfirmStart b;
     packet->RemoveHeader (b);
     NS_TEST_EXPECT_MSG_EQ (a, b, "PEER_LINK_CONFIRM works");
   }
   {
-    PeerLinkFrameStart a;
-    PeerLinkFrameStart::PlinkFrameStartFields fields;
+    PeerLinkCloseStart a;
+    PeerLinkCloseStart::PlinkCloseStartFields fields;
     fields.subtype = (uint8_t)(WifiActionHeader::PEER_LINK_CLOSE);
     fields.capability = 0;
     fields.aid = 10;
     fields.meshId = IeMeshId ("qqq");
     fields.reasonCode = 12;
-    a.SetPlinkFrameStart (fields);
+    a.SetPlinkCloseStart (fields);
     Ptr<Packet> packet = Create<Packet> ();
     packet->AddHeader (a);
-    PeerLinkFrameStart b;
-    b.SetPlinkFrameSubtype ((uint8_t)(WifiActionHeader::PEER_LINK_CLOSE));
+    PeerLinkCloseStart b;
     packet->RemoveHeader (b);
     NS_TEST_EXPECT_MSG_EQ (a, b, "PEER_LINK_CLOSE works");
   }