merge
authorPavel Boyko <boyko@iitp.ru>
Tue, 14 Jul 2009 09:44:09 +0400
changeset 5119 854f1900afd1
parent 5118 3a0893ec9819 (current diff)
parent 5117 591e912d459a (diff)
child 5120 a6c1a26267cf
merge
src/devices/mesh/mesh-wifi-interface-mac.cc
--- a/src/devices/mesh/dot11s/dot11s-mac-header.cc	Tue Jul 14 09:43:58 2009 +0400
+++ b/src/devices/mesh/dot11s/dot11s-mac-header.cc	Tue Jul 14 09:44:09 2009 +0400
@@ -258,17 +258,8 @@
     case MESH_PATH_SELECTION:
       switch (m_actionValue)
         {
-        case PATH_REQUEST:
-          retval.pathSelection = PATH_REQUEST;
-          return retval;
-        case PATH_REPLY:
-          retval.pathSelection = PATH_REPLY;
-          return retval;
-        case PATH_ERROR:
-          retval.pathSelection = PATH_ERROR;
-          return retval;
-        case ROOT_ANNOUNCEMENT:
-          retval.pathSelection = ROOT_ANNOUNCEMENT;
+        case PATH_SELECTION:
+          retval.pathSelection = PATH_SELECTION;
           return retval;
         default:
           NS_FATAL_ERROR ("Unknown mesh path selection action code");
--- a/src/devices/mesh/dot11s/dot11s-mac-header.h	Tue Jul 14 09:43:58 2009 +0400
+++ b/src/devices/mesh/dot11s/dot11s-mac-header.h	Tue Jul 14 09:44:09 2009 +0400
@@ -111,10 +111,7 @@
   /* Compatible with open80211s implementation */
   enum PathSelectionActionValue
   {
-    PATH_REQUEST                = 0,
-    PATH_REPLY                  = 1,
-    PATH_ERROR                  = 2,
-    ROOT_ANNOUNCEMENT           = 3,
+    PATH_SELECTION = 0,
   };
   enum InterworkActionValue
   {
--- a/src/devices/mesh/dot11s/hwmp-protocol-mac.cc	Tue Jul 14 09:43:58 2009 +0400
+++ b/src/devices/mesh/dot11s/hwmp-protocol-mac.cc	Tue Jul 14 09:44:09 2009 +0400
@@ -29,6 +29,7 @@
 #include "hwmp-tag.h"
 #include "ie-dot11s-preq.h"
 #include "ie-dot11s-prep.h"
+#include "ie-dot11s-rann.h"
 
 namespace ns3 {
 namespace dot11s {
@@ -97,44 +98,44 @@
   WifiMeshActionHeader::ActionValue actionValue = actionHdr.GetAction ();
   if(actionHdr.GetCategory () != WifiMeshActionHeader::MESH_PATH_SELECTION)
     return true;
-  switch (actionValue.pathSelection)
+  IeRann rann;
+  IePreq preq;
+  IePrep prep;
+  IePerr perr;
+  while (packet->RemoveHeader (rann))
+  {
+    NS_LOG_WARN("RANN is not supported!");
+  }
+  while (packet->RemoveHeader (preq))
   {
-    case WifiMeshActionHeader::PATH_REQUEST:
-      {
-        IePreq preq;
-        m_stats.rxPreq ++;
-        packet->RemoveHeader (preq);
-        if(preq.GetOriginatorAddress () == m_protocol->GetAddress ())
-          return false;
-        if (preq.GetTtl () == 0)
-          return false;
-        preq.DecrementTtl ();
-        m_protocol->ReceivePreq (preq, header.GetAddr2 (), m_ifIndex, header.GetAddr3 (), m_parent->GetLinkMetric(header.GetAddr2 ()));
-        return false;
-      }
-    case WifiMeshActionHeader::PATH_REPLY:
-      {
-        IePrep prep;
-        m_stats.rxPrep ++;
-        packet->RemoveHeader (prep);
-        if(prep.GetTtl () == 0)
-          return false;
-        prep.DecrementTtl ();
-        m_protocol->ReceivePrep (prep, header.GetAddr2 (), m_ifIndex, header.GetAddr3 (), m_parent->GetLinkMetric(header.GetAddr2 ()));
-        return false;
-      }
-    case WifiMeshActionHeader::PATH_ERROR:
-      {
-        IePerr perr;
-        m_stats.rxPerr ++;
-        packet->RemoveHeader (perr);
-        m_protocol->ReceivePerr (perr, header.GetAddr2 (), m_ifIndex, header.GetAddr3 ());
-        return false;
-      }
-    case WifiMeshActionHeader::ROOT_ANNOUNCEMENT:
-      return false;
+    m_stats.rxPreq ++;
+    if (preq.GetOriginatorAddress () == m_protocol->GetAddress ())
+      continue;
+    if (preq.GetTtl () == 0)
+      continue;
+    preq.DecrementTtl ();
+    m_protocol->ReceivePreq (preq, header.GetAddr2 (), m_ifIndex, header.GetAddr3 (), m_parent->GetLinkMetric(header.GetAddr2 ()));
   }
-  return true;
+  while (packet->RemoveHeader (prep))
+  {
+    m_stats.rxPrep ++;
+    if (prep.GetTtl () == 0)
+      continue;
+    prep.DecrementTtl ();
+    m_protocol->ReceivePrep (prep, header.GetAddr2 (), m_ifIndex, header.GetAddr3 (), m_parent->GetLinkMetric(header.GetAddr2 ()));
+  }
+  std::vector<IePerr::FailedDestination> failedDestinations;
+  while (packet->RemoveHeader (perr))
+  {
+    m_stats.rxPerr ++;
+    std::vector<IePerr::FailedDestination> destinations = perr.GetAddressUnitVector ();
+    for(std::vector<IePerr::FailedDestination>::const_iterator i = destinations.begin (); i != destinations.end (); i ++)
+      failedDestinations.push_back (*i);
+  }
+  if (failedDestinations.size () > 0)
+    m_protocol->ReceivePerr (failedDestinations, header.GetAddr2 (), m_ifIndex, header.GetAddr3 ());
+  NS_ASSERT(packet->GetSize () == 0);
+  return false;
 }
 
 bool
@@ -161,58 +162,38 @@
   m_stats.txData ++;
   m_stats.txDataBytes += packet->GetSize ();
   MeshHeader meshHdr;
-  meshHdr.SetMeshSeqno(tag.GetSeqno());
-  meshHdr.SetMeshTtl(tag.GetTtl());
-  packet->AddHeader(meshHdr);
-  header.SetAddr1(tag.GetAddress());
+  meshHdr.SetMeshSeqno (tag.GetSeqno());
+  meshHdr.SetMeshTtl (tag.GetTtl());
+  packet->AddHeader (meshHdr);
+  header.SetAddr1 (tag.GetAddress());
   return true;
 }
+WifiMeshActionHeader
+HwmpProtocolMac::GetWifiMeshActionHeader ()
+{
+  WifiMeshActionHeader actionHdr;
+  WifiMeshActionHeader::ActionValue action;
+  action.pathSelection = WifiMeshActionHeader::PATH_SELECTION;
+  actionHdr.SetAction (WifiMeshActionHeader::MESH_PATH_SELECTION, action);
+  return actionHdr;
+}
 void
 HwmpProtocolMac::SendPreq(IePreq preq)
 {
-  m_preqQueue.push_back (preq);
-  SendOnePreq ();
+  NS_LOG_FUNCTION_NOARGS ();
+  std::vector<IePreq> preq_vector;
+  preq_vector.push_back(preq);
+  SendPreq(preq_vector);
 }
 void
-HwmpProtocolMac::RequestDestination (Mac48Address dst, uint32_t originator_seqno, uint32_t dst_seqno)
+HwmpProtocolMac::SendPreq(std::vector<IePreq> preq)
 {
-  for(std::vector<IePreq>::iterator i = m_preqQueue.begin (); i != m_preqQueue.end (); i ++)
-    if(i->MayAddAddress(m_protocol->GetAddress ()))
-    {
-      i->AddDestinationAddressElement (m_protocol->GetDoFlag(), m_protocol->GetRfFlag(), dst, dst_seqno);
-      return;
-    }
-  IePreq preq;
-  //fill PREQ:
-  preq.SetHopcount (0);
-  preq.SetTTL (m_protocol->GetMaxTtl ());
-  preq.SetPreqID (m_protocol->GetNextPreqId ());
-  preq.SetOriginatorAddress (m_protocol->GetAddress ());
-  preq.SetOriginatorSeqNumber (originator_seqno);
-  preq.SetLifetime (m_protocol->GetActivePathLifetime ());
-  preq.AddDestinationAddressElement (m_protocol->GetDoFlag (), m_protocol->GetRfFlag (), dst, dst_seqno);
-  m_preqQueue.push_back (preq);
-  //set iterator position to my preq:
-  SendOnePreq ();
-}
-void
-HwmpProtocolMac::SendOnePreq ()
-{
-  if(m_preqTimer.IsRunning ())
-    return;
-  if (m_preqQueue.size () == 0)
-    return;
-  //reschedule sending PREQ
-  NS_ASSERT (!m_preqTimer.IsRunning());
-  m_preqTimer = Simulator::Schedule (m_protocol->GetPreqMinInterval (), &HwmpProtocolMac::SendOnePreq, this);
-  Ptr<Packet> packet  = Create<Packet> ();
-  packet->AddHeader(m_preqQueue[0]);
-  //Action header:
-  WifiMeshActionHeader actionHdr;
-  WifiMeshActionHeader::ActionValue action;
-  action.pathSelection = WifiMeshActionHeader::PATH_REQUEST;
-  actionHdr.SetAction (WifiMeshActionHeader::MESH_PATH_SELECTION, action);
-  packet->AddHeader (actionHdr);
+  Ptr<Packet> packet = Create<Packet> ();
+  for(std::vector<IePreq>::const_iterator i = preq.begin (); i != preq.end (); i ++)
+  {
+    packet->AddHeader (*i);
+  }
+  packet->AddHeader (GetWifiMeshActionHeader ());
   //create 802.11 header:
   WifiMacHeader hdr;
   hdr.SetAction ();
@@ -230,60 +211,51 @@
     m_stats.txMgtBytes += packet->GetSize ();
     m_parent->SendManagementFrame(packet, hdr);
   }
-  //erase queue
-  m_preqQueue.erase (m_preqQueue.begin());
 }
 void
-HwmpProtocolMac::SendOnePerr()
+HwmpProtocolMac::RequestDestination (Mac48Address dst, uint32_t originator_seqno, uint32_t dst_seqno)
 {
-  if(m_perrTimer.IsRunning ())
-    return;
-  if(m_myPerr.receivers.size () >= m_protocol->GetUnicastPerrThreshold ())
+  NS_LOG_FUNCTION_NOARGS ();
+  for(std::vector<IePreq>::iterator i = m_myPreq.begin (); i != m_myPreq.end(); i ++)
   {
-    m_myPerr.receivers.clear ();
-    m_myPerr.receivers.push_back (Mac48Address::GetBroadcast ());
+    if(i->IsFull ())
+      continue;
+    NS_ASSERT (i->GetDestCount () > 0);
+    i->AddDestinationAddressElement (m_protocol->GetDoFlag(), m_protocol->GetRfFlag(), dst, dst_seqno);
   }
-  m_perrTimer = Simulator::Schedule (m_protocol->GetPerrMinInterval (), &HwmpProtocolMac::SendOnePerr, this);
-//Create packet
-  Ptr<Packet> packet  = Create<Packet> ();
-  packet->AddHeader(m_myPerr.perr);
-  //Action header:
-  WifiMeshActionHeader actionHdr;
-  WifiMeshActionHeader::ActionValue action;
-  action.pathSelection = WifiMeshActionHeader::PATH_ERROR;
-  actionHdr.SetAction (WifiMeshActionHeader::MESH_PATH_SELECTION, action);
-  packet->AddHeader (actionHdr);
-  //create 802.11 header:
-  WifiMacHeader hdr;
-  hdr.SetAction ();
-  hdr.SetDsNotFrom ();
-  hdr.SetDsNotTo ();
-  hdr.SetAddr2 (m_parent->GetAddress ());
-  hdr.SetAddr3 (m_protocol->GetAddress ());
-  //Send Management frame
-  for(std::vector<Mac48Address>::const_iterator i = m_myPerr.receivers.begin (); i != m_myPerr.receivers.end (); i ++)
-  {
-    hdr.SetAddr1 (*i);
-    m_stats.txPerr ++;
-    m_stats.txMgt ++;
-    m_stats.txMgtBytes += packet->GetSize ();
-    m_parent->SendManagementFrame(packet, hdr);
-  }
-  m_myPerr.perr.ResetPerr ();
-  m_myPerr.receivers.clear ();
+  IePreq preq;
+  preq.SetHopcount (0);
+  preq.SetTTL (m_protocol->GetMaxTtl ());
+  preq.SetPreqID (m_protocol->GetNextPreqId ());
+  preq.SetOriginatorAddress (m_protocol->GetAddress ());
+  preq.SetOriginatorSeqNumber (originator_seqno);
+  preq.SetLifetime (m_protocol->GetActivePathLifetime ());
+  preq.AddDestinationAddressElement (m_protocol->GetDoFlag(), m_protocol->GetRfFlag(), dst, dst_seqno);
+  m_myPreq.push_back(preq);
+  SendMyPreq ();
+}
+void
+HwmpProtocolMac::SendMyPreq ()
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  if(m_preqTimer.IsRunning ())
+    return;
+  if(m_myPreq.size () == 0)
+    return;
+  //reschedule sending PREQ
+  NS_ASSERT (!m_preqTimer.IsRunning());
+  m_preqTimer = Simulator::Schedule (m_protocol->GetPreqMinInterval (), &HwmpProtocolMac::SendMyPreq, this);
+  SendPreq (m_myPreq);
+  m_myPreq.clear ();
 }
 void
 HwmpProtocolMac::SendPrep (IePrep prep, Mac48Address receiver)
 {
+  NS_LOG_FUNCTION_NOARGS ();
   //Create packet
   Ptr<Packet> packet  = Create<Packet> ();
-  packet->AddHeader(prep);
-  //Action header:
-  WifiMeshActionHeader actionHdr;
-  WifiMeshActionHeader::ActionValue action;
-  action.pathSelection = WifiMeshActionHeader::PATH_REPLY;
-  actionHdr.SetAction (WifiMeshActionHeader::MESH_PATH_SELECTION, action);
-  packet->AddHeader (actionHdr);
+  packet->AddHeader (prep);
+  packet->AddHeader (GetWifiMeshActionHeader ());
   //create 802.11 header:
   WifiMacHeader hdr;
   hdr.SetAction ();
@@ -299,19 +271,91 @@
   m_parent->SendManagementFrame(packet, hdr);
 }
 void
-HwmpProtocolMac::SendPerr(IePerr perr, std::vector<Mac48Address> receivers)
+HwmpProtocolMac::ForwardPerr(std::vector<IePerr::FailedDestination> failedDestinations, std::vector<Mac48Address> receivers)
 {
-  m_myPerr.perr.Merge(perr);
-  for(unsigned int i = 0; i < receivers.size (); i ++)
+  NS_LOG_FUNCTION_NOARGS ();
+  Ptr<Packet> packet  = Create<Packet> ();
+  IePerr perr;
+  for(std::vector<IePerr::FailedDestination>::const_iterator i = failedDestinations.begin (); i != failedDestinations.end (); i ++)
+  {
+    if(!perr.IsFull ())
+      perr.AddAddressUnit (*i);
+    else
+    {
+      packet->AddHeader (perr);
+      perr.ResetPerr ();
+    }
+  }
+  if(perr.GetNumOfDest () > 0)
+    packet->AddHeader (perr);
+  packet->AddHeader (GetWifiMeshActionHeader ());
+  //create 802.11 header:
+  WifiMacHeader hdr;
+  hdr.SetAction ();
+  hdr.SetDsNotFrom ();
+  hdr.SetDsNotTo ();
+  hdr.SetAddr2 (m_parent->GetAddress ());
+  hdr.SetAddr3 (m_protocol->GetAddress ());
+  if(receivers.size () >= m_protocol->GetUnicastPerrThreshold ())
+  {
+    receivers.clear ();
+    receivers.push_back (Mac48Address::GetBroadcast ());
+  }
+  //Send Management frame
+  for(std::vector<Mac48Address>::const_iterator i = m_myPerr.receivers.begin (); i != m_myPerr.receivers.end (); i ++)
   {
-    bool should_add = true;
-    for (unsigned int j = 0; j < m_myPerr.receivers.size (); j ++)
-      if(receivers[j] == m_myPerr.receivers[i])
-        should_add = false;
-    if(should_add)
-      m_myPerr.receivers.push_back(receivers[i]);
+    hdr.SetAddr1 (*i);
+    m_stats.txPerr ++;
+    m_stats.txMgt ++;
+    m_stats.txMgtBytes += packet->GetSize ();
+    m_parent->SendManagementFrame(packet, hdr);
+  }
+}
+void
+HwmpProtocolMac::InitiatePerr (std::vector<IePerr::FailedDestination> failedDestinations, std::vector<Mac48Address> receivers)
+{
+  //All duplicates in PERR are checked here, and there is no reason to
+  //check it at any athoer place
+  {
+    std::vector<Mac48Address>::const_iterator end = receivers.end();
+    for(std::vector<Mac48Address>::const_iterator i = receivers.begin (); i != end; i ++)
+    {
+      bool should_add = true;
+      for (std::vector<Mac48Address>::const_iterator j = m_myPerr.receivers.begin (); j != m_myPerr.receivers.end (); j ++)
+        if ((*i) == (*j))
+          should_add = false;
+      if (should_add)
+        m_myPerr.receivers.push_back(*i);
+    }
   }
-  SendOnePerr ();
+  {
+    std::vector<IePerr::FailedDestination>::const_iterator end =  failedDestinations.end ();
+    for(std::vector<IePerr::FailedDestination>::const_iterator i = failedDestinations.begin (); i != end; i ++)
+    {
+      bool should_add = true;
+      for
+        (
+         std::vector<IePerr::FailedDestination>::const_iterator j = m_myPerr.destinations.begin ();
+         j != m_myPerr.destinations.end ();
+         j ++)
+        if ( ((*i).destination == (*j).destination) && ((*j).seqnum > (*i).seqnum) )
+          should_add = false;
+      if (should_add)
+        m_myPerr.destinations.push_back(*i);
+    }
+  }
+  SendMyPerr ();
+}
+void
+HwmpProtocolMac::SendMyPerr()
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  if(m_perrTimer.IsRunning ())
+    return;
+  m_perrTimer = Simulator::Schedule (m_protocol->GetPerrMinInterval (), &HwmpProtocolMac::SendMyPerr, this);
+  ForwardPerr (m_myPerr.destinations, m_myPerr.receivers);
+  m_myPerr.destinations.clear ();
+  m_myPerr.receivers.clear ();
 }
 uint32_t
 HwmpProtocolMac::GetLinkMetric(Mac48Address peerAddress) const
--- a/src/devices/mesh/dot11s/hwmp-protocol-mac.h	Tue Jul 14 09:43:58 2009 +0400
+++ b/src/devices/mesh/dot11s/hwmp-protocol-mac.h	Tue Jul 14 09:44:09 2009 +0400
@@ -23,6 +23,7 @@
 #define HWMP_STATE_H
 
 #include "ns3/mesh-wifi-interface-mac-plugin.h"
+#include "ie-dot11s-preq.h"
 #include "ie-dot11s-perr.h"
 
 namespace ns3 {
@@ -32,6 +33,7 @@
 namespace dot11s {
 
 class HwmpProtocol;
+class WifiMeshActionHeader;
 class IePreq;
 class IePrep;
 class IePerr;
@@ -57,12 +59,17 @@
   
 private:
   friend class HwmpProtocol;
-  
+  ///\returns a path selection action header
+  static WifiMeshActionHeader GetWifiMeshActionHeader ();
   ///\name Intercation with HWMP:
   //\{
-  void SendPreq(IePreq preq);
-  void SendPrep(IePrep prep, Mac48Address receiver);
-  void SendPerr(IePerr perr, std::vector<Mac48Address> receivers);
+  void SendPreq (IePreq preq);
+  void SendPreq (std::vector<IePreq> preq);
+  void SendPrep (IePrep prep, Mac48Address receiver);
+  //Forward a peth error
+  void ForwardPerr(std::vector<IePerr::FailedDestination> destinations, std::vector<Mac48Address> receivers);
+  // initiate my own path error
+  void InitiatePerr (std::vector<IePerr::FailedDestination> destinations, std::vector<Mac48Address> receivers);
   /** \brief Request a destination. If can not send preq immediately -
    * add a destination to exisying PREQ generated by me and stored in
    * PREQ queue
@@ -73,8 +80,8 @@
   //\}
   
   /// Sends one PREQ when PreqMinInterval after last PREQ expires (if any PREQ exists in rhe queue)
-  void SendOnePreq ();
-  void SendOnePerr ();
+  void SendMyPreq ();
+  void SendMyPerr ();
   /// \return metric to HWMP protocol, needed only by metrics to add
   //peer as routing entry
   uint32_t GetLinkMetric (Mac48Address peerAddress) const;
@@ -87,16 +94,16 @@
   uint32_t m_ifIndex;
   Ptr<HwmpProtocol> m_protocol;
   
-  ///\name PREQ queue and PREQ timer:
+  ///\name my PREQ and PREQ timer:
   //\{
-  EventId  m_preqTimer;
-  std::vector<IePreq>  m_preqQueue;
+  EventId m_preqTimer;
+  std::vector<IePreq>  m_myPreq;
   //\}
   ///\name PERR timer and stored path error
   //\{
   EventId m_perrTimer;
   struct MyPerr {
-    IePerr perr;
+    std::vector<IePerr::FailedDestination> destinations;
     std::vector<Mac48Address> receivers;
   };
   MyPerr m_myPerr;
--- a/src/devices/mesh/dot11s/hwmp-protocol.cc	Tue Jul 14 09:43:58 2009 +0400
+++ b/src/devices/mesh/dot11s/hwmp-protocol.cc	Tue Jul 14 09:44:09 2009 +0400
@@ -34,7 +34,6 @@
 #include "airtime-metric.h"
 #include "ie-dot11s-preq.h"
 #include "ie-dot11s-prep.h"
-#include "ie-dot11s-perr.h"
 
 NS_LOG_COMPONENT_DEFINE ("HwmpProtocol");
 
@@ -304,7 +303,7 @@
     if(result.retransmitter != Mac48Address::GetBroadcast ())
     {
       std::vector<IePerr::FailedDestination> destinations = m_rtable->GetUnreachableDestinations (result.retransmitter);
-      MakePathError (destinations);
+      InitiatePathError (MakePathError (destinations));
     }
     m_stats.totalDropped ++;
     return false;
@@ -317,6 +316,7 @@
     uint32_t dst_seqno = 0;
     if(result.retransmitter != Mac48Address::GetBroadcast ())
       dst_seqno = result.seqnum;
+    m_stats.initiatedPreq ++;
     for(HwmpProtocolMacMap::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); i ++)
       i->second->RequestDestination(destination, originator_seqno, dst_seqno);
   }
@@ -558,28 +558,25 @@
   prep_sender->second->SendPrep (prep, result.retransmitter);
 }
 void
-HwmpProtocol::ReceivePerr (IePerr perr, Mac48Address from, uint32_t interface, Mac48Address fromMp)
+HwmpProtocol::ReceivePerr (std::vector<IePerr::FailedDestination> destinations, Mac48Address from, uint32_t interface, Mac48Address fromMp)
 {
   //Acceptance cretirea:
   NS_LOG_DEBUG("I am "<<GetAddress ()<<", received PERR from "<<from);
-  std::vector<IePerr::FailedDestination> destinations = perr.GetAddressUnitVector ();
+  std::vector<IePerr::FailedDestination> retval;
   HwmpRtable::LookupResult result;
   for(unsigned int i = 0; i < destinations.size (); i ++)
   {
     result = m_rtable->LookupReactive (destinations[i].destination);
-    if (
+    if (!(
         (result.retransmitter != from) ||
         (result.ifIndex != interface) ||
         (result.seqnum > destinations[i].seqnum)
-        )
-    {
-      perr.DeleteAddressUnit(destinations[i].destination);
-      continue;
-    }
+        ))
+      retval.push_back(destinations[i]);
   }
-  if(perr.GetNumOfDest () == 0)
+  if(retval.size() == 0)
     return;
-  MakePathError (destinations);
+  ForwardPathError (MakePathError (retval));
 }
 void
 HwmpProtocol::SendPrep (
@@ -604,8 +601,7 @@
   HwmpProtocolMacMap::const_iterator prep_sender = m_interfaces.find (interface);
   NS_ASSERT(prep_sender != m_interfaces.end ());
   prep_sender->second->SendPrep (prep, retransmitter);
-  //m_prepCallback (prep, retransmitter);
-
+  m_stats.initiatedPrep ++;
 }
 bool
 HwmpProtocol::Install (Ptr<MeshPointDevice> mp)
@@ -641,7 +637,7 @@
   if(status)
     return;
   std::vector<IePerr::FailedDestination> destinations = m_rtable->GetUnreachableDestinations (peerAddress);
-  MakePathError (destinations);
+  InitiatePathError (MakePathError (destinations));
 }
 void
 HwmpProtocol::SetNeighboursCallback(Callback<std::vector<Mac48Address>, uint32_t> cb)
@@ -664,28 +660,47 @@
   }
   return false;
 }
-void
+HwmpProtocol::PathError
 HwmpProtocol::MakePathError (std::vector<IePerr::FailedDestination> destinations)
 {
+  PathError retval;
   //HwmpRtable increments a sequence number as written in 11B.9.7.2
-  std::vector<std::pair<uint32_t, Mac48Address> > receivers = GetPerrReceivers (destinations);
-  if(receivers.size () == 0)
-    return;
-  IePerr perr;
+  retval.receivers = GetPerrReceivers (destinations);
+  if(retval.receivers.size () == 0)
+    return retval;
+  m_stats.initiatedPerr ++;
   for(unsigned int i = 0; i < destinations.size (); i ++)
   {
-    perr.AddAddressUnit(destinations[i]);
+    retval.destinations.push_back(destinations[i]);
     m_rtable->DeleteReactivePath(destinations[i].destination);
   }
+  return retval;
+}
+void
+HwmpProtocol::InitiatePathError(PathError perr)
+{
   for(HwmpProtocolMacMap::const_iterator i =  m_interfaces.begin (); i != m_interfaces.end (); i ++)
   {
     std::vector<Mac48Address> receivers_for_interface;
-    for(unsigned int j = 0; j < receivers.size(); j ++)
-      if(i->first == receivers[j].first)
-        receivers_for_interface.push_back(receivers[j].second);
-    i->second->SendPerr (perr, receivers_for_interface);
+    for(unsigned int j = 0; j < perr.receivers.size(); j ++)
+      if(i->first == perr.receivers[j].first)
+        receivers_for_interface.push_back(perr.receivers[j].second);
+    i->second->InitiatePerr (perr.destinations, receivers_for_interface);
   }
 }
+void
+HwmpProtocol::ForwardPathError(PathError perr)
+{
+  for(HwmpProtocolMacMap::const_iterator i =  m_interfaces.begin (); i != m_interfaces.end (); i ++)
+  {
+    std::vector<Mac48Address> receivers_for_interface;
+    for(unsigned int j = 0; j < perr.receivers.size(); j ++)
+      if(i->first == perr.receivers[j].first)
+        receivers_for_interface.push_back(perr.receivers[j].second);
+    i->second->ForwardPerr (perr.destinations, receivers_for_interface);
+  }
+}
+
 std::vector<std::pair<uint32_t, Mac48Address> >
 HwmpProtocol::GetPerrReceivers (std::vector<IePerr::FailedDestination> failedDest)
 {
@@ -964,7 +979,10 @@
     "txBytes=\"" << txBytes << "\" "
     "droppedTtl=\"" << droppedTtl << "\" "
     "totalQueued=\"" << totalQueued << "\" "
-    "totalDropped=\"" << totalDropped << "\"/>\n";
+    "totalDropped=\"" << totalDropped << "\" "
+    "initiatedPreq=\"" << initiatedPreq << "\" "
+    "initiatedPrep=\"" << initiatedPrep << "\" "
+    "initiatedPerr=\"" << initiatedPerr << "\"\n";
 }
 void
 HwmpProtocol::Report (std::ostream & os) const
--- a/src/devices/mesh/dot11s/hwmp-protocol.h	Tue Jul 14 09:43:58 2009 +0400
+++ b/src/devices/mesh/dot11s/hwmp-protocol.h	Tue Jul 14 09:44:09 2009 +0400
@@ -90,7 +90,7 @@
   //\{
   void ReceivePreq(IePreq preq, Mac48Address from, uint32_t interface, Mac48Address fromMp, uint32_t metric);
   void ReceivePrep(IePrep prep, Mac48Address from, uint32_t interface, Mac48Address fromMp, uint32_t metric);
-  void ReceivePerr(IePerr perr, Mac48Address from, uint32_t interface, Mac48Address fromMp);
+  void ReceivePerr(std::vector<IePerr::FailedDestination>, Mac48Address from, uint32_t interface, Mac48Address fromMp);
   void SendPrep (
       Mac48Address src,
       Mac48Address dst,
@@ -100,9 +100,25 @@
       uint32_t destinationSN,
       uint32_t lifetime,
       uint32_t interface);
-  
-  ///\brief forms a path error information element when list of destination fails on a given interface
-  void MakePathError (std::vector<IePerr::FailedDestination> destinations);
+  /**
+   * \brief Structure of path error: IePerr and list of receivers:
+   * interfaces and MAC address
+   */
+  struct PathError
+  {
+    std::vector<IePerr::FailedDestination> destinations;
+    /// interface-address
+    std::vector<std::pair<uint32_t, Mac48Address> > receivers;
+  };
+  /**
+   * \brief forms a path error information element when list of destination fails on a given interface
+   * \attention removes all entries from routing table!
+   */
+  PathError MakePathError (std::vector<IePerr::FailedDestination> destinations);
+  ///\brief Forwards a received path error
+  void ForwardPathError (PathError perr);
+  ///\brief Pasess a selg-generated PERR to interface-plugin
+  void InitiatePathError (PathError perr);
   /// \return list of addresses where a PERR should be sent to
   std::vector<std::pair<uint32_t, Mac48Address> > GetPerrReceivers (std::vector<IePerr::FailedDestination> failedDest);
   
@@ -151,9 +167,12 @@
     uint16_t droppedTtl;
     uint16_t totalQueued;
     uint16_t totalDropped;
+    uint16_t initiatedPreq;
+    uint16_t initiatedPrep;
+    uint16_t initiatedPerr;
 
     void Print (std::ostream & os) const;
-    Statistics () : txUnicast (0), txBroadcast (0), txBytes (0), droppedTtl (0), totalQueued (0), totalDropped (0) {}
+    Statistics () : txUnicast (0), txBroadcast (0), txBytes (0), droppedTtl (0), totalQueued (0), totalDropped (0), initiatedPreq (0), initiatedPrep (0), initiatedPerr (0) {}
   };
   Statistics m_stats;
   ///\}
--- a/src/devices/mesh/dot11s/ie-dot11s-perr.cc	Tue Jul 14 09:43:58 2009 +0400
+++ b/src/devices/mesh/dot11s/ie-dot11s-perr.cc	Tue Jul 14 09:44:09 2009 +0400
@@ -32,9 +32,8 @@
 void
 IePerr::PrintInformation (std::ostream &os) const
 {
-  os << "Number of failed destinations: = " << m_numOfDest;
-  NS_ASSERT (m_numOfDest == m_addressUnits.size ());
-  for (unsigned int j = 0; j < m_numOfDest; j++)
+  os << "Number of failed destinations: = " << m_addressUnits.size ();
+  for (unsigned int j = 0; j < m_addressUnits.size (); j++)
     {
       os << "Failed destination address: = "<< m_addressUnits[j].destination <<
         ", sequence number = " << m_addressUnits[j].seqnum;
@@ -42,22 +41,20 @@
   os << "\n";
 
 }
-IePerr::IePerr ():
-    m_numOfDest (0)
+IePerr::IePerr ()
 {
 }
 uint8_t
 IePerr::GetNumOfDest ()
 {
-  return m_numOfDest;
+  return m_addressUnits.size ();
 }
 void
 IePerr::SerializeInformation (Buffer::Iterator i) const
 {
   i.WriteU8 (0);
-  i.WriteU8 (m_numOfDest);
-  NS_ASSERT (m_numOfDest == m_addressUnits.size ());
-  for (unsigned int j = 0; j < m_numOfDest; j++)
+  i.WriteU8 (m_addressUnits.size ());
+  for (unsigned int j = 0; j < m_addressUnits.size (); j++)
     {
       WriteTo (i, m_addressUnits[j].destination);
       i.WriteHtolsbU32 (m_addressUnits[j].seqnum);
@@ -68,10 +65,10 @@
 {
   Buffer::Iterator i = start;
   i.Next (1); //Mode flags is not used now
-  m_numOfDest = i.ReadU8 ();
-  NS_ASSERT ((2+10*m_numOfDest) == length);
+  uint8_t numOfDest = i.ReadU8 ();
+  NS_ASSERT ((2+10*numOfDest) == length);
   length = 0; //to avoid compiler warning in optimized builds
-  for (unsigned int j = 0; j < m_numOfDest; j++)
+  for (unsigned int j = 0; j < numOfDest; j++)
     {
       FailedDestination unit;
       ReadFrom (i,unit.destination);
@@ -87,8 +84,7 @@
   uint8_t retval =
      1 //ModeFlags
     +1 //NumOfDests
-    +6*m_numOfDest
-    +4*m_numOfDest;
+    +(6+4) * m_addressUnits.size ();
   return retval;
 }
 
@@ -98,10 +94,15 @@
   for (unsigned int i = 0; i < m_addressUnits.size (); i ++)
     if (m_addressUnits[i].destination == unit.destination)
       return;
+  if((m_addressUnits.size () + 1) * 10 + 2 > 255)
+    return;
   m_addressUnits.push_back (unit);
-  m_numOfDest++;
 }
-
+bool
+IePerr::IsFull () const
+{
+  return (GetSerializedSize () + 10 > 255);
+}
 std::vector<IePerr::FailedDestination>
 IePerr::GetAddressUnitVector () const
 {
@@ -113,34 +114,18 @@
   for (std::vector<FailedDestination>::iterator i = m_addressUnits.begin (); i != m_addressUnits.end(); i ++)
     if (i->destination == address)
       {
-        m_numOfDest --;
         m_addressUnits.erase (i);
         break;
       }
 }
 void
-IePerr::Merge(const IePerr perr)
-{
-  std::vector<FailedDestination> to_merge = perr.GetAddressUnitVector ();
-  for (std::vector<FailedDestination>::iterator i = to_merge.begin (); i != to_merge.end(); i ++)
-  {
-    bool should_add = true;
-    for (std::vector<FailedDestination>::iterator j = m_addressUnits.begin (); j != m_addressUnits.end(); j ++)
-      if ((i->destination == j->destination) && (i->seqnum <= j->seqnum))
-        should_add = false;
-    if(should_add)
-      AddAddressUnit (*i);
-  }
-}
-void
 IePerr::ResetPerr ()
 {
-  m_numOfDest = 0;
   m_addressUnits.clear ();
 }
 bool operator== (const IePerr & a, const IePerr & b)
 {
-  if(a.m_numOfDest != b.m_numOfDest)
+  if(a.m_addressUnits.size () != b.m_addressUnits.size ())
     return false;
   for(unsigned int i = 0; i < a.m_addressUnits.size(); i ++)
   {
@@ -179,10 +164,6 @@
   dest.seqnum = 3;
   a.AddAddressUnit(dest);
   
-  IePerr b = a;
-  b.Merge(a);
-  NS_TEST_ASSERT_EQUAL (a, b);
-  
   result = result && TestRoundtripSerialization (a);
   return result;
 }
--- a/src/devices/mesh/dot11s/ie-dot11s-perr.h	Tue Jul 14 09:43:58 2009 +0400
+++ b/src/devices/mesh/dot11s/ie-dot11s-perr.h	Tue Jul 14 09:44:09 2009 +0400
@@ -44,9 +44,9 @@
   uint8_t   GetNumOfDest ();
 
   void AddAddressUnit (struct FailedDestination unit);
+  bool IsFull () const;
   std::vector<FailedDestination> GetAddressUnitVector () const;
   void DeleteAddressUnit (Mac48Address address);
-  void Merge(const IePerr perr);
   void ResetPerr ();
 private:
   WifiElementId ElementId () const{
@@ -57,7 +57,6 @@
   void PrintInformation (std::ostream& os) const;
   uint8_t  GetInformationSize () const;
 private:
-  uint8_t   m_numOfDest;
   std::vector<FailedDestination> m_addressUnits;
   friend bool operator== (const IePerr & a, const IePerr & b);
 };
--- a/src/devices/mesh/dot11s/ie-dot11s-prep.cc	Tue Jul 14 09:43:58 2009 +0400
+++ b/src/devices/mesh/dot11s/ie-dot11s-prep.cc	Tue Jul 14 09:44:09 2009 +0400
@@ -188,8 +188,7 @@
     +4 //Lifetime
     +4 //metric
     +6 //Originator address
-    +4 //Originator seqno
-    +1; //destination count
+    +4; //Originator seqno
   return retval;
 };
 void
--- a/src/devices/mesh/dot11s/ie-dot11s-preq.cc	Tue Jul 14 09:43:58 2009 +0400
+++ b/src/devices/mesh/dot11s/ie-dot11s-preq.cc	Tue Jul 14 09:44:09 2009 +0400
@@ -336,6 +336,7 @@
   for (std::vector<Ptr<DestinationAddressUnit> >::const_iterator i = m_destinations.begin (); i != m_destinations.end(); i++ )
     if ((*i)->GetDestinationAddress () == dest_address)
       return;
+  //TODO: check overflow
   Ptr<DestinationAddressUnit>new_element = Create<DestinationAddressUnit> ();
   new_element->SetFlags (doFlag, rfFlag, false);
   new_element->SetDestinationAddress (dest_address);
@@ -355,7 +356,7 @@
       }
 }
 void
-IePreq::ClearDestinationAddressElement ()
+IePreq::ClearDestinationAddressElements ()
 {
   int i;
   for (std::vector<Ptr<DestinationAddressUnit> >::iterator j = m_destinations.begin (); j != m_destinations.end(); j++)
@@ -363,6 +364,7 @@
   for (i = 0; i < m_destCount; i ++)
     m_destinations.pop_back ();
   m_destinations.clear ();
+  m_destCount = 0;
 }
 bool operator== (const DestinationAddressUnit & a, const DestinationAddressUnit & b)
 {
@@ -408,8 +410,15 @@
     return false;
   if(m_destinations[0]->GetDestinationAddress () == Mac48Address::GetBroadcast ())
     return false;
+  if((GetInformationSize () + 11) > 255)
+    return false;
   return true;
 }
+bool
+IePreq::IsFull () const
+{
+  return ((GetInformationSize () + 11) > 255);
+}
 #ifdef RUN_SELF_TESTS
 
 /// Built-in self test for IePreq
--- a/src/devices/mesh/dot11s/ie-dot11s-preq.h	Tue Jul 14 09:43:58 2009 +0400
+++ b/src/devices/mesh/dot11s/ie-dot11s-preq.h	Tue Jul 14 09:44:09 2009 +0400
@@ -64,20 +64,30 @@
 public:
   IePreq ();
   ~IePreq ();
+  /**
+   * Add a destination address unit: flags, destination and sequence
+   * number
+   */
   void AddDestinationAddressElement (
     bool doFlag,
     bool rfFlag,
     Mac48Address dest_address,
     uint32_t dest_seq_number
   );
+  /// Delete a destination address unit by destination
   void DelDestinationAddressElement (Mac48Address dest_address);
-  void ClearDestinationAddressElement ();
+  /// Clear PREQ: remove all destinations
+  void ClearDestinationAddressElements ();
+  /// Get all destinations, which are stored in PREQ:
   std::vector<Ptr<DestinationAddressUnit> > GetDestinationList ();
+  /// SetProper flags which indicate that PREQ is unicast
   void SetUnicastPreq ();
   /*
    * \brief In proactive case: need we send PREP
    */
   void SetNeedNotPrep ();
+  ///\name Setters for fields:
+  ///\{
   void SetHopcount (uint8_t hopcount);
   void SetTTL (uint8_t ttl);
   void SetPreqID (uint32_t id);
@@ -86,7 +96,9 @@
   void SetLifetime (uint32_t lifetime);
   void SetMetric (uint32_t metric);
   void SetDestCount (uint8_t dest_count);
-
+  ///\}
+  ///\name Getters for fields:
+  ///\{
   bool  IsUnicastPreq () const;
   bool  IsNeedNotPrep () const;
   uint8_t  GetHopCount () const;
@@ -97,6 +109,8 @@
   uint32_t GetLifetime () const;
   uint32_t GetMetric () const;
   uint8_t  GetDestCount () const;
+  ///\}
+  /// Handle TTL and Metric:
   void  DecrementTtl ();
   void  IncrementMetric (uint32_t metric);
   /*
@@ -104,7 +118,7 @@
    * this preq is not proactive
    */
   bool MayAddAddress(Mac48Address originator);
-
+  bool IsFull () const;
 private:
   WifiElementId ElementId () const{
     return IE11S_PREQ;
--- a/src/devices/mesh/flame/flame-installer.cc	Tue Jul 14 09:43:58 2009 +0400
+++ b/src/devices/mesh/flame/flame-installer.cc	Tue Jul 14 09:44:09 2009 +0400
@@ -52,11 +52,18 @@
 {
   mp->Report (os);
   // TODO report flame counters
+  Ptr <FlameProtocol> flame = mp->GetObject<FlameProtocol> ();
+  NS_ASSERT(flame != 0);
+  flame->Report (os);
 }
 void
 FlameStack::ResetStats (const Ptr<MeshPointDevice> mp)
 {
   mp->ResetStats ();
   // TODO reset flame counters
+  Ptr <FlameProtocol> flame = mp->GetObject<FlameProtocol> ();
+  NS_ASSERT(flame != 0);
+
+  flame->ResetStats ();
 }
 } //namespace ns3
--- a/src/devices/mesh/flame/flame-protocol-mac.cc	Tue Jul 14 09:43:58 2009 +0400
+++ b/src/devices/mesh/flame/flame-protocol-mac.cc	Tue Jul 14 09:44:09 2009 +0400
@@ -51,6 +51,11 @@
   }
   tag.receiver = header.GetAddr1 ();
   tag.transmitter = header.GetAddr2 ();
+  if(tag.receiver == Mac48Address::GetBroadcast ())
+    m_stats.rxBroadcast ++;
+  else
+    m_stats.rxUnicast ++;
+  m_stats.rxBytes += packet->GetSize ();
   packet->AddPacketTag (tag);
   return true;
 }
@@ -65,6 +70,11 @@
     NS_FATAL_ERROR ("FLAME tag must exist here");
   }
   header.SetAddr1 (tag.receiver);
+  if(tag.receiver == Mac48Address::GetBroadcast ())
+    m_stats.txBroadcast ++;
+  else
+    m_stats.txUnicast ++;
+  m_stats.txBytes += packet->GetSize ();
   return true;
 }
 uint16_t
@@ -73,12 +83,29 @@
   return m_parent->GetFrequencyChannel ();
 }
 void
+FlameProtocolMac::Statistics::Print (std::ostream &os) const
+{
+  os << "<Statistics "
+    "txUnicast=\"" << txUnicast << "\" "
+    "txBroadcast=\"" << txBroadcast << "\" "
+    "txBytes=\"" << txBytes << "\" "
+    "rxUnicast=\"" << rxUnicast << "\" "
+    "rxBroadcast=\"" << rxBroadcast << "\" "
+    "rxBytes=\"" << rxBytes << "\"/>\n";
+}
+void
 FlameProtocolMac::Report (std::ostream & os) const
 {
+  os << "<FlameProtocolMac\n"
+    "address =\""<< m_parent->GetAddress () <<"\">\n";
+  m_stats.Print(os);
+  os << "</FlameProtocolMac>\n";
+
 }
 void
 FlameProtocolMac::ResetStats ()
 {
+  m_stats = Statistics ();
 }
 
 } //namespace flame
--- a/src/devices/mesh/flame/flame-protocol-mac.h	Tue Jul 14 09:43:58 2009 +0400
+++ b/src/devices/mesh/flame/flame-protocol-mac.h	Tue Jul 14 09:44:09 2009 +0400
@@ -57,6 +57,23 @@
   uint32_t m_ifIndex;
   Ptr<MeshWifiInterfaceMac> m_parent;
   ///\}
+  ///\name Statistics:
+  ///\{
+  struct Statistics
+  {
+    uint16_t txUnicast;
+    uint16_t txBroadcast;
+    uint32_t txBytes;
+    uint16_t rxUnicast;
+    uint16_t rxBroadcast;
+    uint32_t rxBytes;
+
+    void Print (std::ostream & os) const;
+    Statistics () : txUnicast (0), txBroadcast (0), txBytes (0), rxUnicast (0), rxBroadcast (0), rxBytes (0) {}
+  };
+  Statistics m_stats;
+  ///\}
+
 };
 } //namespace flame
 } //namespace ns3
--- a/src/devices/mesh/flame/flame-protocol.cc	Tue Jul 14 09:43:58 2009 +0400
+++ b/src/devices/mesh/flame/flame-protocol.cc	Tue Jul 14 09:44:09 2009 +0400
@@ -157,8 +157,13 @@
     flameHdr.SetProtocol (protocolType);
     flameHdr.SetOrigDst (destination);
     flameHdr.SetOrigSrc (source);
+    m_stats.txBytes += packet->GetSize ();
     packet->AddHeader (flameHdr);
     tag.receiver = result.retransmitter;
+    if(result.retransmitter == Mac48Address::GetBroadcast ())
+      m_stats.txBroadcast ++;
+    else
+      m_stats.txUnicast ++;
     NS_LOG_DEBUG("Source: send packet with RA = " << tag.receiver);
     packet->AddPacketTag (tag);
     routeReply (true, packet, source, destination, FLAME_PROTOCOL, result.ifIndex);
@@ -179,6 +184,7 @@
             "received packet with SA = GetAddress (), RA = " << tag.receiver << 
             ", TA = " << tag.transmitter <<
             ", I am "<<GetAddress ());
+      m_stats.totalDropped ++;
       return false;
     }
     if(destination == Mac48Address::GetBroadcast ())
@@ -187,9 +193,11 @@
       NS_ASSERT (HandleDataFrame(flameHdr.GetSeqno (), source, flameHdr, tag.transmitter, sourceIface));
       FlameTag tag (Mac48Address::GetBroadcast ());
       flameHdr.AddCost (1);
+      m_stats.txBytes += packet->GetSize ();
       packet->AddHeader (flameHdr);
       packet->AddPacketTag (tag);
       routeReply (true, packet, source, destination, FLAME_PROTOCOL, FlameRtable::INTERFACE_ANY);
+      m_stats.txBroadcast ++;
       return true;
     }
     else
@@ -204,10 +212,16 @@
           NS_LOG_DEBUG("unicast packet dropped, because no route! I am "<<GetAddress () << 
             ", RA = " << tag.receiver << 
             ", TA = " << tag.transmitter);
+          m_stats.totalDropped ++;
           return false;
         }
       }
       tag.receiver = result.retransmitter;
+      if(result.retransmitter == Mac48Address::GetBroadcast ())
+        m_stats.txBroadcast ++;
+      else
+        m_stats.txUnicast ++;
+      m_stats.txBytes += packet->GetSize ();
       flameHdr.AddCost (1);
       packet->AddHeader (flameHdr);
       packet->AddPacketTag (tag);
@@ -285,10 +299,43 @@
   if(result.seqnum >= seqno)
     return true;
   if (flameHdr.GetCost () > m_maxCost)
+  {
+    m_stats.droppedTtl ++;
     return true;
+  }
   m_rtable->AddPath (source, receiver, fromInterface, flameHdr.GetCost (), flameHdr.GetSeqno ());
   return false;
 }
+//Statistics:
+void FlameProtocol::Statistics::Print (std::ostream & os) const
+{
+  os << "<Statistics "
+    "txUnicast=\"" << txUnicast << "\" "
+    "txBroadcast=\"" << txBroadcast << "\" "
+    "txBytes=\"" << txBytes << "\" "
+    "droppedTtl=\"" << droppedTtl << "\" "
+    "totalDropped=\"" << totalDropped << "\"/>\n";
+}
+
+void
+FlameProtocol::Report (std::ostream & os) const
+{
+  os << "<Flame "
+    "address=\"" << m_address << "\"\n"
+    "broadcastInterval=\"" << m_broadcastInterval.GetSeconds () << "\"\n"
+    "maxCost=\"" << (uint16_t)m_maxCost << "\">\n";
+  m_stats.Print (os);
+  for(FlamePluginMap::const_iterator plugin = m_interfaces.begin (); plugin != m_interfaces.end (); plugin ++)
+    plugin->second->Report(os);
+  os << "</Flame>\n";
+}
+void
+FlameProtocol::ResetStats ()
+{
+  m_stats = Statistics ();
+  for(FlamePluginMap::const_iterator plugin = m_interfaces.begin (); plugin != m_interfaces.end (); plugin ++)
+    plugin->second->ResetStats ();
+}
 
 } //namespace flame
 } //namespace ns3
--- a/src/devices/mesh/flame/flame-protocol.h	Tue Jul 14 09:43:58 2009 +0400
+++ b/src/devices/mesh/flame/flame-protocol.h	Tue Jul 14 09:44:09 2009 +0400
@@ -33,9 +33,16 @@
  * \ingroup mesh
  * \defgroup flame FLAME 
  * 
- * \brief Forwarding LAyer for Meshing protocol
+ * \brief Forwarding LAyer for MEshing protocol
  * 
- * TODO add relevant references
+ * Simple L2.5 mesh routing protocol developed by 
+ * Herman Elfrink <herman.elfrink@ti-wmc.nl> and presented in
+ * "Easy Wireless: broadband ad-hoc networking for emergency services"
+ * by Maurits de Graaf et. al. at The Sixth Annual Mediterranean Ad Hoc 
+ * Networking WorkShop, Corfu, Greece, June 12-15, 2007
+ *
+ * see also Linux kernel mailing list discussion at 
+ * http://lkml.org/lkml/2006/5/23/82
  */
 namespace ns3 {
 namespace flame {
@@ -126,6 +133,21 @@
   uint16_t m_myLastSeqno;
   /// Routing table:
   Ptr<FlameRtable> m_rtable;
+  ///\name Statistics:
+  ///\{
+  struct Statistics
+  {
+    uint16_t txUnicast;
+    uint16_t txBroadcast;
+    uint32_t txBytes;
+    uint16_t droppedTtl;
+    uint16_t totalDropped;
+    void Print (std::ostream & os) const;
+    Statistics () : txUnicast (0), txBroadcast (0), txBytes (0), droppedTtl (0), totalDropped (0) {}
+  };
+  Statistics m_stats;
+  ///\}
+
 };
 } //namespace flame
 } //namespace ns3
--- a/src/devices/mesh/mesh-wifi-interface-mac.cc	Tue Jul 14 09:43:58 2009 +0400
+++ b/src/devices/mesh/mesh-wifi-interface-mac.cc	Tue Jul 14 09:44:09 2009 +0400
@@ -31,6 +31,7 @@
 #include "ns3/simulator.h"
 #include "ns3/yans-wifi-phy.h"
 #include "ns3/pointer.h"
+#include "ns3/qos-tag.h"
 
 
 NS_LOG_COMPONENT_DEFINE ("MeshWifiInterfaceMac");
@@ -62,18 +63,7 @@
           &MeshWifiInterfaceMac::GetBeaconGeneration
           ),
         MakeBooleanChecker ()
-        )
-        
-    .AddAttribute ("BE", "The DcaTxop object",
-                   PointerValue (),
-                   MakePointerAccessor (&MeshWifiInterfaceMac::GetBE,
-                                        &MeshWifiInterfaceMac::SetBE),
-                   MakePointerChecker<DcaTxop> ())
-    .AddAttribute ("VO", "The DcaTxop object",
-                   PointerValue (),
-                   MakePointerAccessor (&MeshWifiInterfaceMac::GetVO,
-                                        &MeshWifiInterfaceMac::SetVO),
-                   MakePointerChecker<DcaTxop> ());
+        );
   return tid;
 }
 
@@ -199,10 +189,8 @@
 {
   NS_LOG_FUNCTION (this << stationManager);
   m_stationManager = stationManager;
-  NS_ASSERT(m_BE != 0);
-  m_BE->SetWifiRemoteStationManager (stationManager);
-  NS_ASSERT(m_VO != 0);
-  m_VO->SetWifiRemoteStationManager (stationManager);
+  for (Queues::const_iterator i = m_queues.begin (); i != m_queues.end (); i ++)
+    i->second->SetWifiRemoteStationManager (stationManager);
   m_beaconDca->SetWifiRemoteStationManager (stationManager);
   m_low->SetWifiRemoteStationManager (stationManager);
 }
@@ -293,8 +281,7 @@
   m_low = 0;
   m_dcfManager = 0;
   m_phy = 0;
-  m_BE = 0;
-  m_VO = 0;
+  m_queues.clear ();
   m_beaconSendEvent.Cancel ();
   m_beaconDca = 0;
 
@@ -387,6 +374,11 @@
   hdr.SetAddr4 (from);
   hdr.SetDsFrom ();
   hdr.SetDsTo ();
+  // Fill QoS fields:
+  hdr.SetQosAckPolicy (WifiMacHeader::NORMAL_ACK);
+  hdr.SetQosNoEosp ();
+  hdr.SetQosNoAmsdu ();
+  hdr.SetQosTxopLimit (0);
 
   // Address 1 is unknwon here. Routing plugin is responsible to correctly set it.
   hdr.SetAddr1 (Mac48Address ());
@@ -414,9 +406,16 @@
         }
       destination->RecordDisassociated ();
     }
+  //Classify: application sets a tag, which is removed here
+  // Get Qos tag:
+  AccessClass ac = AC_BE;
+  QosTag tag;
+  if(packet->RemovePacketTag (tag))
+    ac = QosUtilsMapTidToAc (tag.Get ());
   m_stats.sentFrames ++;
   m_stats.sentBytes += packet->GetSize ();
-  m_BE->Queue (packet, hdr);
+  NS_ASSERT(m_queues.find(ac) != m_queues.end ());
+  m_queues[ac]->Queue (packet, hdr);
 }
 
 void
@@ -431,7 +430,12 @@
     }
   m_stats.sentFrames ++;
   m_stats.sentBytes += packet->GetSize ();
-  m_VO->Queue (packet, header);
+  Queues::iterator i = m_queues.find (AC_VO);
+  if (i == m_queues.end ())
+  {
+    NS_FATAL_ERROR("Voice queue is not set up!");
+  }
+  m_queues[AC_VO]->Queue (packet, header);
 }
 
 SupportedRates
@@ -606,6 +610,9 @@
       if (drop) return; // plugin drops frame
     }
 
+  // Check if QoS tag exists and add it:
+  if (hdr->IsQosData ())
+    packet->AddPacketTag (QosTag (hdr->GetQosTid ()));
   // Forward data up
   if (hdr->IsData ())
       ForwardUp (packet, hdr->GetAddr4(), hdr->GetAddr3());
@@ -671,28 +678,28 @@
   m_stats = Statistics::Statistics ();
 }
 void
-MeshWifiInterfaceMac::SetBE (Ptr<DcaTxop> dcaTxop)
+MeshWifiInterfaceMac::SetQueue (Ptr<DcaTxop> queue, AccessClass ac)
 {
-  m_BE = dcaTxop;
-  m_BE->SetLow (m_low);
-  m_BE->SetManager (m_dcfManager);
-}
-void
-MeshWifiInterfaceMac::SetVO (Ptr<DcaTxop> dcaTxop)
-{
-  m_VO = dcaTxop;
-  m_VO->SetLow (m_low);
-  m_VO->SetManager (m_dcfManager);
+  Queues::iterator i = m_queues.find(ac);
+  if(i != m_queues.end ())
+  {
+    NS_LOG_WARN("Queue is already set!");
+    return;
+  }
+  m_queues.insert (std::make_pair(ac, queue));
+  m_queues[ac]->SetLow (m_low);
+  m_queues[ac]->SetManager (m_dcfManager);
 }
 Ptr<DcaTxop>
-MeshWifiInterfaceMac::GetBE () const
+MeshWifiInterfaceMac::GetQueue (AccessClass ac)
 {
-  return m_BE;
-}
-Ptr<DcaTxop>
-MeshWifiInterfaceMac::GetVO () const
-{
-  return m_VO;
+  Queues::iterator i = m_queues.find(ac);
+  if(i != m_queues.end ())
+  {
+    NS_LOG_WARN("Queue is not found! Check access class!");
+    return 0;
+  }
+  return i->second;
 }
 } // namespace ns3
 
--- a/src/devices/mesh/mesh-wifi-interface-mac.h	Tue Jul 14 09:43:58 2009 +0400
+++ b/src/devices/mesh/mesh-wifi-interface-mac.h	Tue Jul 14 09:44:09 2009 +0400
@@ -33,7 +33,7 @@
 #include "ns3/wifi-mac.h"
 #include "ns3/mesh-wifi-interface-mac-plugin.h"
 #include "ns3/event-id.h"
-
+#include "qos-utils.h"
 namespace ns3 {
 
 class WifiMacHeader;
@@ -160,11 +160,9 @@
   void ResetStats ();
   /// Enable/disable beacons
   void SetBeaconGeneration (bool enable);
+  void SetQueue (Ptr<DcaTxop> queue, AccessClass ac);
 private:
-  Ptr<DcaTxop> GetBE(void) const;
-  void SetBE (Ptr<DcaTxop> dcaTxop);
-  Ptr<DcaTxop> GetVO(void) const;
-  void SetVO (Ptr<DcaTxop> dcaTxop);
+  Ptr<DcaTxop> GetQueue (AccessClass ac);
   /// Frame receive handler
   void  Receive (Ptr<Packet> packet, WifiMacHeader const *hdr);
   /// Forward frame to mesh point
@@ -183,10 +181,8 @@
 private:
   ///\name Wifi MAC internals
   //\{
-  Ptr<DcaTxop>   m_BE;
-  Ptr<DcaTxop>   m_BK;
-  Ptr<DcaTxop>   m_VI;
-  Ptr<DcaTxop>   m_VO;
+  typedef std::map<AccessClass, Ptr<DcaTxop> > Queues;
+  Queues m_queues;
   Ptr<DcaTxop>   m_beaconDca;
   Ptr<WifiRemoteStationManager> m_stationManager;
   Ptr<WifiPhy>   m_phy;
--- a/src/devices/wifi/qos-tag.cc	Tue Jul 14 09:43:58 2009 +0400
+++ b/src/devices/wifi/qos-tag.cc	Tue Jul 14 09:44:09 2009 +0400
@@ -43,7 +43,11 @@
   return GetTypeId ();
 }
 
-QosTag::QosTag()
+QosTag::QosTag ():
+  m_tid (0)
+{}
+QosTag::QosTag (uint8_t tid):
+  m_tid (tid)
 {}
 
 uint32_t 
--- a/src/devices/wifi/qos-tag.h	Tue Jul 14 09:43:58 2009 +0400
+++ b/src/devices/wifi/qos-tag.h	Tue Jul 14 09:44:09 2009 +0400
@@ -33,6 +33,7 @@
   virtual TypeId GetInstanceTypeId (void) const;
   
   QosTag ();
+  QosTag (uint8_t tid);
   virtual void Serialize (TagBuffer i) const;
   virtual void Deserialize (TagBuffer i);
   virtual uint32_t GetSerializedSize () const;
--- a/src/devices/wifi/qos-utils.cc	Tue Jul 14 09:43:58 2009 +0400
+++ b/src/devices/wifi/qos-utils.cc	Tue Jul 14 09:44:09 2009 +0400
@@ -28,30 +28,23 @@
   switch (tid) {
   case 0 :
     return AC_BE;
-    break;
   case 1 :
     return AC_BK;
-    break;
   case 2 :
     return AC_BK;
-    break;
   case 3 :
     return AC_BE;
-    break;
   case 4 :
     return AC_VI;
-    break;
   case 5 :
     return AC_VI;
-    break;
   case 6 :
     return AC_VO;
-    break;
   case 7 : 
     return AC_VO;
-    break;
+  default:
+    return AC_BE;
   }
-  return AC_UNDEF;
 }
 
 uint8_t
--- a/src/helper/mesh-interface-helper.cc	Tue Jul 14 09:43:58 2009 +0400
+++ b/src/helper/mesh-interface-helper.cc	Tue Jul 14 09:44:09 2009 +0400
@@ -28,8 +28,15 @@
 
 MeshInterfaceHelper::MeshInterfaceHelper ()
 {
-  m_Be.SetTypeId ("ns3::DcaTxop");
-  m_Vo.SetTypeId ("ns3::DcaTxop");
+  m_queues.insert (std::make_pair (AC_VO, ObjectFactory ()));
+  m_queues.insert (std::make_pair (AC_VI, ObjectFactory ()));
+  m_queues.insert (std::make_pair (AC_BE, ObjectFactory ()));
+  m_queues.insert (std::make_pair (AC_BK, ObjectFactory ()));
+
+  m_queues[AC_VO].SetTypeId ("ns3::DcaTxop");
+  m_queues[AC_VI].SetTypeId ("ns3::DcaTxop");
+  m_queues[AC_BE].SetTypeId ("ns3::DcaTxop");
+  m_queues[AC_BK].SetTypeId ("ns3::DcaTxop");
 }
 
 MeshInterfaceHelper::~MeshInterfaceHelper ()
@@ -40,14 +47,6 @@
 {
   MeshInterfaceHelper helper;
   helper.SetType ();
-  helper.SetBeParameters (
-      "MinCw", UintegerValue (15),
-      "MaxCw", UintegerValue (255),
-      "Aifsn", UintegerValue (2));
-  helper.SetVoParameters (
-      "MinCw", UintegerValue (3),
-      "MaxCw", UintegerValue (7),
-      "Aifsn", UintegerValue (2));
   helper.SetRemoteStationManager ("ns3::ArfWifiManager");
   return helper;
 }
@@ -73,26 +72,24 @@
   m_mac.Set (n7, v7);
 }
 void
-MeshInterfaceHelper::SetBeParameters (std::string n0, const AttributeValue &v0,
-                                     std::string n1, const AttributeValue &v1,
-                                     std::string n2, const AttributeValue &v2,
-                                     std::string n3, const AttributeValue &v3)
+MeshInterfaceHelper::SetQueueParameters ( AccessClass ac,
+    std::string n0, const AttributeValue &v0,
+    std::string n1, const AttributeValue &v1,
+    std::string n2, const AttributeValue &v2,
+    std::string n3, const AttributeValue &v3)
 {
-  m_Be.Set (n0, v0);
-  m_Be.Set (n1, v1);
-  m_Be.Set (n2, v2);
-  m_Be.Set (n3, v3);
-}
-void
-MeshInterfaceHelper::SetVoParameters (std::string n0, const AttributeValue &v0,
-                                     std::string n1, const AttributeValue &v1,
-                                     std::string n2, const AttributeValue &v2,
-                                     std::string n3, const AttributeValue &v3)
-{
-  m_Vo.Set (n0, v0);
-  m_Vo.Set (n1, v1);
-  m_Vo.Set (n2, v2);
-  m_Vo.Set (n3, v3);
+  std::map<AccessClass, ObjectFactory>::iterator queue = m_queues.find (ac);
+  if (queue != m_queues.end ())
+    {
+      queue->second.Set (n0, v0);
+      queue->second.Set (n1, v1);
+      queue->second.Set (n2, v2);
+      queue->second.Set (n3, v3);
+    }
+  else
+  {
+    NS_FATAL_ERROR ("Queue is not set!");
+  }
 }
 void 
 MeshInterfaceHelper::SetRemoteStationManager (std::string type,
@@ -137,11 +134,12 @@
 Ptr<WifiMac>
 MeshInterfaceHelper::Create (void) const
 {
-  Ptr<WifiMac> mac = m_mac.Create<WifiMac> ();
-  Ptr<DcaTxop> be = m_Be.Create<DcaTxop> ();
-  Ptr<DcaTxop> vo = m_Vo.Create<DcaTxop> ();
-  mac->SetAttribute ("BE", PointerValue (be));
-  mac->SetAttribute ("VO", PointerValue (vo));
+  Ptr<MeshWifiInterfaceMac> mac = m_mac.Create<MeshWifiInterfaceMac> ();
+  for (std::map<AccessClass, ObjectFactory>::const_iterator i = m_queues.begin (); i != m_queues.end (); i ++)
+  {
+    //Ptr<DcaTxop> dca = i->second->Create ();
+    mac->SetQueue(i->second.Create<DcaTxop> (), i->first);
+  }
   return mac;
 }
 void
--- a/src/helper/mesh-interface-helper.h	Tue Jul 14 09:43:58 2009 +0400
+++ b/src/helper/mesh-interface-helper.h	Tue Jul 14 09:44:09 2009 +0400
@@ -23,6 +23,7 @@
 #include "ns3/wifi-helper.h"
 #include "ns3/wifi-net-device.h"
 #include "ns3/mesh-wifi-interface-mac.h"
+#include "ns3/qos-utils.h"
 namespace ns3 {
 
 class MeshInterfaceHelper : public WifiMacHelper
@@ -51,23 +52,16 @@
                 std::string n6 = "", const AttributeValue &v6 = EmptyAttributeValue (),
                 std::string n7 = "", const AttributeValue &v7 = EmptyAttributeValue ());
   /**
+   * \param ac is access class of the queue to be adjusted
    * \param type the type of ns3::WifiMac to create.
    * \param n%d the name of the attribute to set
    * \param v%d the value of the attribute to set
    */
-  void SetBeParameters ( std::string n0 = "", const AttributeValue &v0 = EmptyAttributeValue (),
-                         std::string n1 = "", const AttributeValue &v1 = EmptyAttributeValue (),
-                         std::string n2 = "", const AttributeValue &v2 = EmptyAttributeValue (),
-                         std::string n3 = "", const AttributeValue &v3 = EmptyAttributeValue ());
-  /**
-   * \param type the type of ns3::WifiMac to create.
-   * \param n%d the name of the attribute to set
-   * \param v%d the value of the attribute to set
-   */
-  void SetVoParameters ( std::string n0 = "", const AttributeValue &v0 = EmptyAttributeValue (),
-                         std::string n1 = "", const AttributeValue &v1 = EmptyAttributeValue (),
-                         std::string n2 = "", const AttributeValue &v2 = EmptyAttributeValue (),
-                         std::string n3 = "", const AttributeValue &v3 = EmptyAttributeValue ());
+  void SetQueueParameters (AccessClass ac,
+      std::string n0 = "", const AttributeValue &v0 = EmptyAttributeValue (),
+      std::string n1 = "", const AttributeValue &v1 = EmptyAttributeValue (),
+      std::string n2 = "", const AttributeValue &v2 = EmptyAttributeValue (),
+      std::string n3 = "", const AttributeValue &v3 = EmptyAttributeValue ());
   /**
    * \param type the type of ns3::WifiRemoteStationManager to create.
    * \param n%d the name of the attribute to set
@@ -104,8 +98,7 @@
   Ptr<WifiMac> Create (void) const;
 
   ObjectFactory m_mac;
-  ObjectFactory m_Be;
-  ObjectFactory m_Vo;
+  std::map<AccessClass, ObjectFactory> m_queues;
   ObjectFactory m_stationManager;
 };