Merge with ns-3-dev.
authorSebastien Vincent <vincent@clarinet.u-strasbg.fr>
Thu, 12 Nov 2009 09:52:54 +0100
changeset 5803 56b5e7ff673a
parent 5802 e93f45bb4bdf (current diff)
parent 5503 c305c6e122c9 (diff)
child 5804 8a41c3e4e8c7
Merge with ns-3-dev.
--- a/AUTHORS	Wed Nov 11 16:25:10 2009 +0100
+++ b/AUTHORS	Thu Nov 12 09:52:54 2009 +0100
@@ -12,23 +12,33 @@
 Craig Dowell (craigdo@ee.washington.edu)
 David Gross (gdavid.devel@gmail.com)
 Tom Henderson (tomhend@u.washington.edu)
-Andrey Mazo (mazo@iitp.ru)
 Sam Jansen (sam.jansen@gmail.com)
 Liu Jian (liujatp@gmail.com)
 Joe Kopena (tjkopena@cs.drexel.edu)
 Aleksey Kovalenko (kovalenko@iitp.ru)
 Mathieu Lacage (mathieu.lacage@sophia.inria.fr)
 Emmanuelle Laprise (emmmanuelle.laprise@bluekazoo.ca)
+Keith Ma (keith.nwsuaf@gmail.com)
 Federico Maguolo (maguolof@dei.unipd.it)
+Antti Makela (zarhan@cc.hut.fi)
 Francesco Malandrino (francesco.malandrino@gmail.com)
+Fabian Mauchle (f1mauchl@hsr.ch)
+Andrey Mazo (mazo@iitp.ru)
 Faker Moatamri (faker.moatamri@sophia.inria.fr)
 Duy Nguyen (duy@soe.ucsc.edu)
+Tommaso Pecorella (tommaso.pecorella@unifi.it)
+Yana Podkosova (yanapdk@rambler.ru)
 Guangyu Pei (guangyu.pei@boeing.com)
 George F. Riley (riley@ece.gatech.edu)
 Providence Salumu Munga (Providence.Salumu@gmail.com, Providence.Salumu_Munga@it-sudparis.eu)
+Guillaume Seguin (guillaume.seguin@sophia.inria.fr)
 Kulin Shah (m.kulin@gmail.com)
+Ewgenij Starostin (estar@cs.tu-berlin.de)
+Adrian S. W. Tam (adrian.sw.tam@gmail.com)
+Wilson Thong (wilsonwk@ee.cityu.edu.hk)
 Mauro Tortonesi (mauro.tortonesi@unife.it)
 Sebastien Vincent (vincent@clarinet.u-strasbg.fr)
 Guillaume Vu-Brugier (gvubrugier@gmail.com)
+Tom Wambold (tom5760@gmail.com)
 Florian Westphal (fw@strlen.de)
 Josh Pelkey (jpelkey@gatech.edu)
--- a/CHANGES.html	Wed Nov 11 16:25:10 2009 +0100
+++ b/CHANGES.html	Thu Nov 12 09:52:54 2009 +0100
@@ -44,6 +44,24 @@
 us a note on ns-developers mailing list.  </p>
 
 <hr>
+<h1>Changes from ns-3.6 to ns-3.7</h1>
+
+<h2>Changes to build system:</h2>
+
+<h2>New API:</h2>
+
+<h2>Changes to existing API:</h2>
+
+<h2>Changed behavior:</h2>
+<ul>
+<li> Changed default value of YansWifiPhy::EnergyDetectionThreshold from
+-140.0 dBm to -96.0 dBm.  Changed default value of 
+YansWifiPhy::CcaModelThreshold from -140.0 dBm to -99.0 dBm.  Rationale
+can be found <a href="http://www.nsnam.org/bugzilla/show_bug.cgi?id=689"> 
+here</a>.
+</ul>
+
+<hr>
 <h1>Changes from ns-3.5 to ns-3.6</h1>
 
 <h2>Changes to build system:</h2>
--- a/RELEASE_NOTES	Wed Nov 11 16:25:10 2009 +0100
+++ b/RELEASE_NOTES	Thu Nov 12 09:52:54 2009 +0100
@@ -1,11 +1,14 @@
 
 		ns-3 RELEASE NOTES
 
-This file contains ns-3 release notes (most recent releases first).
+This file contains ns-3 release notes (most recent releases first).  
 
 All of the ns-3 documentation is accessible from the ns-3 website: 
 http://www.nsnam.org including tutorials: http://www.nsnam.org/tutorials.html
 
+Consult the file CHANGES.html for more detailed information about changed
+API and behavior across ns-3 releases.
+
 Release 3.6
 ===========
 
@@ -21,7 +24,6 @@
   - linux x86_64 gcc 4.4.0, 4.3.2, 4.2.3, 4.2.1, 4.1.3, 3.4.6
   - MacOS X ppc and x86 (gcc 4.0.x and 4.2.x)
   - cygwin gcc 3.4.4 (debug only), gcc 4.3.2 (debug and optimized)
-  - mingw gcc 3.4.5 (debug only)
 
 Not all ns-3 options are available on all platforms; consult the
 wiki for more information:
@@ -78,7 +80,7 @@
 
 Known issues
 ------------
-ns-3 build is known to fail on the following platforms:
+ns-3.6 build is known to fail on the following platforms:
   - gcc 3.3 and earlier
   - optimized builds on gcc 3.4.4 and 3.4.5
   - optimized builds on linux x86 gcc 4.0.x
--- a/examples/stats/README	Wed Nov 11 16:25:10 2009 +0100
+++ b/examples/stats/README	Thu Nov 12 09:52:54 2009 +0100
@@ -14,3 +14,23 @@
 available online on the ns-3 wiki at:
 
 http://www.nsnam.org/wiki/index.php/Statistical_Framework_for_Network_Simulation
+
+*** Using ns-3 with the OMNeT++ analysis tool ***
+
+The stat framework can write out the result in a format that is compatible with the
+output format of OMNeT++ 4 Discrete Event Simulator Framework.
+Use the wifi-example-omnet.sh script to generate the results in OMNeT++ format.
+
+If you want to analyse the results with OMNeT++'s result analyser tool:
+a) Download OMNeT++ 4 and install it. Start the IDE. (www.omnetpp.org)
+b) If you do not want to install the whole simulator framework, there is a seperate 
+   package which contains only the analysis tool from the OMNeT++ package.
+   You can download it from http://omnetpp.org/download/release/omnetpp-scave.tgz
+
+Once you are running the OMNeT++ IDE or the separate analysis tool (SCAVE)
+- Choose File|Import...|Existing Projects into Workspace, then click [Next]
+- Select root directory. (choose the examples/stats directory) and click [Finish]
+
+Double click the wifi-example-omnet.anf in the opened project and select 
+the Chart page to see the created chart. Experiment with the analysis tool and read its
+documentation: http://omnetpp.org/doc/omnetpp40/userguide/ch09.html
--- a/examples/stats/wifi-example-sim.cc	Wed Nov 11 16:25:10 2009 +0100
+++ b/examples/stats/wifi-example-sim.cc	Thu Nov 12 09:52:54 2009 +0100
@@ -200,6 +200,7 @@
   Ptr<CounterCalculator<uint32_t> > totalTx =
     CreateObject<CounterCalculator<uint32_t> >();
   totalTx->SetKey("wifi-tx-frames");
+  totalTx->SetContext("node[0]");
   Config::Connect("/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/Mac/MacTx",
                   MakeBoundCallback(&TxCallback, totalTx));
   data.AddDataCalculator(totalTx);
@@ -211,6 +212,7 @@
   Ptr<PacketCounterCalculator> totalRx =
     CreateObject<PacketCounterCalculator>();
   totalRx->SetKey("wifi-rx-frames");
+  totalRx->SetContext("node[1]");
   Config::Connect("/NodeList/1/DeviceList/*/$ns3::WifiNetDevice/Mac/MacRx",
                   MakeCallback(&PacketCounterCalculator::PacketUpdate,
                                totalRx));
@@ -225,6 +227,7 @@
   Ptr<PacketCounterCalculator> appTx =
     CreateObject<PacketCounterCalculator>();
   appTx->SetKey("sender-tx-packets");
+  appTx->SetContext("node[0]");
   Config::Connect("/NodeList/0/ApplicationList/*/$Sender/Tx",
                   MakeCallback(&PacketCounterCalculator::PacketUpdate,
                                     appTx));
@@ -237,6 +240,7 @@
   Ptr<CounterCalculator<> > appRx =
     CreateObject<CounterCalculator<> >();
   appRx->SetKey("receiver-rx-packets");
+  appRx->SetContext("node[1]");
   receiver->SetCounter(appRx);
   data.AddDataCalculator(appRx);
 
@@ -263,6 +267,7 @@
   Ptr<PacketSizeMinMaxAvgTotalCalculator> appTxPkts =
     CreateObject<PacketSizeMinMaxAvgTotalCalculator>();
   appTxPkts->SetKey("tx-pkt-size");
+  appTxPkts->SetContext("node[0]");
   Config::Connect("/NodeList/0/ApplicationList/*/$Sender/Tx",
                   MakeCallback
                     (&PacketSizeMinMaxAvgTotalCalculator::PacketUpdate,
@@ -277,6 +282,7 @@
   Ptr<TimeMinMaxAvgTotalCalculator> delayStat =
     CreateObject<TimeMinMaxAvgTotalCalculator>();
   delayStat->SetKey("delay");
+  delayStat->SetContext(".");
   receiver->SetDelayTracker(delayStat);
   data.AddDataCalculator(delayStat);
 
--- a/src/common/packet.h	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/common/packet.h	Thu Nov 12 09:52:54 2009 +0100
@@ -32,7 +32,6 @@
 #include "ns3/callback.h"
 #include "ns3/assert.h"
 #include "ns3/ptr.h"
-#include "ns3/deprecated.h"
 
 namespace ns3 {
 
--- a/src/common/pcap-file-test-suite.cc	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/common/pcap-file-test-suite.cc	Thu Nov 12 09:52:54 2009 +0100
@@ -107,7 +107,7 @@
   std::stringstream filename;
   uint32_t n = rand ();
   filename << n;
-  m_testFilename = "/tmp/" + filename.str () + ".pcap";
+  m_testFilename = GetTempDir () + filename.str () + ".pcap";
 }
 
 void
@@ -218,7 +218,7 @@
   std::stringstream filename;
   uint32_t n = rand ();
   filename << n;
-  m_testFilename = "/tmp/" + filename.str () + ".pcap";
+  m_testFilename = GetTempDir () + filename.str () + ".pcap";
 }
 
 void
@@ -317,7 +317,7 @@
   std::stringstream filename;
   uint32_t n = rand ();
   filename << n;
-  m_testFilename = "/tmp/" + filename.str () + ".pcap";
+  m_testFilename = GetTempDir () + filename.str () + ".pcap";
 }
 
 void
@@ -416,7 +416,7 @@
   std::stringstream filename;
   uint32_t n = rand ();
   filename << n;
-  m_testFilename = "/tmp/" + filename.str () + ".pcap";
+  m_testFilename = GetTempDir () + filename.str () + ".pcap";
 }
 
 void
@@ -607,7 +607,7 @@
   std::stringstream filename;
   uint32_t n = rand ();
   filename << n;
-  m_testFilename = "/tmp/" + filename.str () + ".pcap";
+  m_testFilename = GetTempDir () + filename.str () + ".pcap";
 }
 
 void
--- a/src/contrib/net-anim/animation-interface.cc	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/contrib/net-anim/animation-interface.cc	Thu Nov 12 09:52:54 2009 +0100
@@ -21,9 +21,15 @@
 #include <stdio.h>
 #include <sstream>
 
+#include "ns3/net-anim-config.h"
+
 // Socket related includes
-#include <sys/socket.h>
-#include <netinet/in.h>
+#if defined(HAVE_SYS_SOCKET_H) && defined(HAVE_NETINET_IN_H)
+# include <sys/socket.h>
+# include <netinet/in.h>
+#else
+#include <fcntl.h>
+#endif
 
 // ns3 includes
 #include "ns3/animation-interface.h"
@@ -58,6 +64,7 @@
 
 bool AnimationInterface::SetServerPort (uint16_t port)
 {
+#if defined(HAVE_SYS_SOCKET_H) && defined(HAVE_NETINET_IN_H)
   int s = socket (AF_INET, SOCK_STREAM, 0);
   struct sockaddr_in addr;
   addr.sin_family = AF_INET;
@@ -77,6 +84,8 @@
   int t = 1;
   setsockopt (s, SOL_SOCKET, SO_LINGER, &t, sizeof(t));
   return true;
+#endif
+  return false;//never reached unless the above is disabled
 }
 
 bool AnimationInterface::SetInternalAnimation ()
--- a/src/contrib/net-anim/point-to-point-dumbbell-helper.cc	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/contrib/net-anim/point-to-point-dumbbell-helper.cc	Thu Nov 12 09:52:54 2009 +0100
@@ -21,10 +21,6 @@
 #include <iostream>
 #include <sstream>
 
-// Socket related includes
-#include <sys/socket.h>
-#include <netinet/in.h>
-
 // ns3 includes
 #include "ns3/animation-interface.h"
 #include "ns3/point-to-point-dumbbell-helper.h"
--- a/src/contrib/net-anim/wscript	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/contrib/net-anim/wscript	Thu Nov 12 09:52:54 2009 +0100
@@ -1,5 +1,11 @@
 ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
 
+def configure(conf):
+    conf.check(header_name='sys/socket.h', define_name='HAVE_SYS_SOCKET_H')
+    conf.check(header_name='netinet/in.h', define_name='HAVE_NETINET_IN_H')
+    conf.write_config_header('ns3/net-anim-config.h', top=True)
+
+
 def build(bld):
     obj = bld.create_ns3_module('net-anim')
     obj.source = [
--- a/src/contrib/stats/basic-data-calculators.h	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/contrib/stats/basic-data-calculators.h	Thu Nov 12 09:52:54 2009 +0100
@@ -29,7 +29,8 @@
   //------------------------------------------------------------
   //--------------------------------------------
   template <typename T  = uint32_t>
-  class MinMaxAvgTotalCalculator : public DataCalculator {
+  class MinMaxAvgTotalCalculator : public DataCalculator,
+                                   public StatisticalSummary {
   public:
     MinMaxAvgTotalCalculator();
     virtual ~MinMaxAvgTotalCalculator();
@@ -38,6 +39,15 @@
 
     virtual void Output(DataOutputCallback &callback) const;
 
+    long getCount() const { return m_count; }
+    double getSum() const { return m_total; }
+    double getMin() const { return m_min; }
+    double getMax() const { return m_max; }
+    double getMean() const { return m_total / (double)m_count; }
+    double getStddev() const { return NaN; } // unsupported
+    double getVariance() const { return NaN; } // unsupported
+    double getSqrSum() const { return NaN; } // unsupported
+
   protected:
     virtual void DoDispose(void);
 
@@ -86,23 +96,15 @@
     }
     // end MinMaxAvgTotalCalculator::Update
   }
+
   template <typename T>
   void
   MinMaxAvgTotalCalculator<T>::Output(DataOutputCallback &callback) const
   {
-    callback.OutputSingleton(m_key, "count", m_count);
-    if (m_count > 0) {
-      callback.OutputSingleton(m_key, "total", m_total);
-      callback.OutputSingleton(m_key, "average", m_total/m_count);
-      callback.OutputSingleton(m_key, "max", m_max);
-      callback.OutputSingleton(m_key, "min", m_min);
-    }
-    // end MinMaxAvgTotalCalculator::Output
+      callback.OutputStatistic(m_context, m_key, this);
   }
 
 
-
-
   //------------------------------------------------------------
   //--------------------------------------------
   template <typename T  = uint32_t>
@@ -178,7 +180,7 @@
   void
   CounterCalculator<T>::Output(DataOutputCallback &callback) const
   {
-    callback.OutputSingleton(m_key, "count", m_count);
+    callback.OutputSingleton(m_context, m_key, m_count);
     // end CounterCalculator::Output
   }
 
--- a/src/contrib/stats/data-calculator.cc	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/contrib/stats/data-calculator.cc	Thu Nov 12 09:52:54 2009 +0100
@@ -27,6 +27,8 @@
 
 NS_LOG_COMPONENT_DEFINE("DataCalculator");
 
+static double zero = 0;
+const double ns3::NaN = zero / zero;
 
 //--------------------------------------------------------------
 //----------------------------------------------
@@ -70,6 +72,20 @@
 
 //----------------------------------------------
 void
+DataCalculator::SetContext(const std::string context)
+{
+  m_context = context;
+  // end DataCalculator::SetContext
+}
+
+std::string
+DataCalculator::GetContext() const
+{
+  return m_context;
+  // end DataCalculator::GetContext
+}
+//----------------------------------------------
+void
 DataCalculator::Enable()
 {
   m_enabled = true;
--- a/src/contrib/stats/data-calculator.h	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/contrib/stats/data-calculator.h	Thu Nov 12 09:52:54 2009 +0100
@@ -26,9 +26,56 @@
 #include "ns3/simulator.h"
 
 namespace ns3 {
+  extern const double NaN;
+  inline bool isNaN(double x) { return x != x; }
 
   class DataOutputCallback;
 
+  class StatisticalSummary {
+	  public:
+	    /**
+	     * Returns the number of the observations.
+	     */
+	    virtual long getCount() const = 0;
+
+	    /**
+	     * Returns the sum of the values.
+	     * @see getWeightedSum()
+	     */
+	    virtual double getSum() const = 0;
+
+	    /**
+	     * Returns the sum of the squared values.
+	     * @see getWeightedSqrSum()
+	     */
+	    virtual double getSqrSum() const = 0;
+
+	    /**
+	     * Returns the minimum of the values.
+	     */
+	    virtual double getMin() const = 0;
+
+	    /**
+	     * Returns the maximum of the values.
+	     */
+	    virtual double getMax() const = 0;
+
+	    /**
+	     * Returns the mean of the (weighted) observations.
+	     */
+	    virtual double getMean() const = 0;
+
+	    /**
+	     * Returns the standard deviation of the (weighted) observations.
+	     */
+	    virtual double getStddev() const = 0;
+
+	    /**
+	     * Returns the variance of the (weighted) observations.
+	     */
+	    virtual double getVariance() const = 0;
+  };
+
   //------------------------------------------------------------
   //--------------------------------------------
   class DataCalculator : public Object {
@@ -43,6 +90,9 @@
     void SetKey(const std::string key);
     std::string GetKey() const;
 
+    void SetContext(const std::string context);
+    std::string GetContext() const;
+
     virtual void Start(const Time& startTime);
     virtual void Stop(const Time& stopTime);
 
@@ -52,6 +102,7 @@
     bool m_enabled;  // Descendant classes *must* check & respect m_enabled!
 
     std::string m_key;
+    std::string m_context;
 
     virtual void DoDispose(void);
 
--- a/src/contrib/stats/data-output-interface.h	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/contrib/stats/data-output-interface.h	Thu Nov 12 09:52:54 2009 +0100
@@ -23,6 +23,7 @@
 
 #include "ns3/object.h"
 #include "ns3/nstime.h"
+#include "ns3/data-calculator.h"
 
 namespace ns3 {
 
@@ -52,6 +53,10 @@
   public:
     virtual ~DataOutputCallback() {}
 
+    virtual void OutputStatistic(std::string key,
+                                 std::string variable,
+                                 const StatisticalSummary *statSum) = 0;
+
     virtual void OutputSingleton(std::string key,
                                  std::string variable,
                                  int val) = 0;
--- a/src/contrib/stats/omnet-data-output.cc	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/contrib/stats/omnet-data-output.cc	Thu Nov 12 09:52:54 2009 +0100
@@ -19,6 +19,7 @@
  */
 
 #include <fstream>
+#include <cstdlib>
 
 #include "ns3/log.h"
 #include "ns3/nstime.h"
@@ -54,26 +55,31 @@
 }
 
 //----------------------------------------------
+
+inline bool isNumeric(const std::string& s) {
+  char *endp;
+  strtod(s.c_str(), &endp);
+  return endp == s.c_str() + s.size();
+}
+
 void
 OmnetDataOutput::Output(DataCollector &dc)
 {
 
   std::ofstream scalarFile;
-  std::string fn = m_filePrefix + ".sca";
-  scalarFile.open(fn.c_str(), std::ios_base::app);
+  std::string fn = m_filePrefix +"-"+dc.GetRunLabel()+ ".sca";
+  scalarFile.open(fn.c_str(), std::ios_base::out);
 
-  scalarFile << std::endl;
+  // TODO add timestamp to the runlevel
   scalarFile << "run " << dc.GetRunLabel() << std::endl;
-  scalarFile << std::endl;
   scalarFile << "attr experiment \"" << dc.GetExperimentLabel()
             << "\"" << std::endl;
   scalarFile << "attr strategy \"" << dc.GetStrategyLabel()
             << "\"" << std::endl;
-  scalarFile << "attr input \"" << dc.GetInputLabel()
+  scalarFile << "attr measurement \"" << dc.GetInputLabel()
             << "\"" << std::endl;
   scalarFile << "attr description \"" << dc.GetDescription()
             << "\"" << std::endl;
-  scalarFile << std::endl;
 
   for (MetadataList::iterator i = dc.MetadataBegin();
        i != dc.MetadataEnd(); i++) {
@@ -83,7 +89,18 @@
   }
 
   scalarFile << std::endl;
-
+  if (isNumeric(dc.GetInputLabel())) {
+     scalarFile << "scalar . measurement \"" << dc.GetInputLabel()
+            << "\"" << std::endl;
+  }
+  for (MetadataList::iterator i = dc.MetadataBegin();
+       i != dc.MetadataEnd(); i++) {
+    std::pair<std::string, std::string> blob = (*i);
+    if (isNumeric(blob.second)) {
+       scalarFile << "scalar . \"" << blob.first << "\" \"" << blob.second << "\""
+               << std::endl;
+    }
+  }
   OmnetOutputCallback callback(&scalarFile);
 
   for (DataCalculatorList::iterator i = dc.DataCalculatorBegin();
@@ -97,6 +114,7 @@
   // end OmnetDataOutput::Output
 }
 
+
 OmnetDataOutput::OmnetOutputCallback::OmnetOutputCallback
   (std::ostream *scalar) :
   m_scalar(scalar)
@@ -104,42 +122,92 @@
 }
 
 void
-OmnetDataOutput::OmnetOutputCallback::OutputSingleton(std::string key,
-                                                      std::string variable,
+OmnetDataOutput::OmnetOutputCallback::OutputStatistic(std::string context,
+                                                      std::string name,
+                                                      const StatisticalSummary *statSum)
+{
+	if (context == "")
+		context = ".";
+	if (name == "")
+		name = "\"\"";
+	(*m_scalar) << "statistic " << context << " " << name << std::endl;
+	if (!isNaN(statSum->getCount()))
+		(*m_scalar) << "field count " << statSum->getCount() << std::endl;
+	if (!isNaN(statSum->getSum()))
+		(*m_scalar) << "field sum " << statSum->getSum() << std::endl;
+	if (!isNaN(statSum->getMean()))
+		(*m_scalar) << "field mean " << statSum->getMean() << std::endl;
+	if (!isNaN(statSum->getMin()))
+		(*m_scalar) << "field min " << statSum->getMin() << std::endl;
+	if (!isNaN(statSum->getMax()))
+		(*m_scalar) << "field max " << statSum->getMax() << std::endl;
+	if (!isNaN(statSum->getSqrSum()))
+		(*m_scalar) << "field sqrsum " << statSum->getSqrSum() << std::endl;
+	if (!isNaN(statSum->getStddev()))
+		(*m_scalar) << "field stddev " << statSum->getStddev() << std::endl;
+}
+
+void
+OmnetDataOutput::OmnetOutputCallback::OutputSingleton(std::string context,
+                                                      std::string name,
                                                       int val)
 {
-  (*m_scalar) << "scalar " << key << " " << variable << " " << val << std::endl;
+	if (context == "")
+		context = ".";
+	if (name == "")
+		name = "\"\"";
+  (*m_scalar) << "scalar " << context << " " << name << " " << val << std::endl;
   // end OmnetDataOutput::OmnetOutputCallback::OutputSingleton
 }
+
 void
-OmnetDataOutput::OmnetOutputCallback::OutputSingleton(std::string key,
-                                                      std::string variable,
+OmnetDataOutput::OmnetOutputCallback::OutputSingleton(std::string context,
+                                                      std::string name,
                                                       uint32_t val)
 {
-  (*m_scalar) << "scalar " << key << " " << variable << " " << val << std::endl;
+	if (context == "")
+		context = ".";
+	if (name == "")
+		name = "\"\"";
+  (*m_scalar) << "scalar " << context << " " << name << " " << val << std::endl;
   // end OmnetDataOutput::OmnetOutputCallback::OutputSingleton
 }
+
 void
-OmnetDataOutput::OmnetOutputCallback::OutputSingleton(std::string key,
-                                                      std::string variable,
+OmnetDataOutput::OmnetOutputCallback::OutputSingleton(std::string context,
+                                                      std::string name,
                                                       double val)
 {
-  (*m_scalar) << "scalar " << key << " " << variable << " " << val << std::endl;
+	if (context == "")
+		context = ".";
+	if (name == "")
+		name = "\"\"";
+    (*m_scalar) << "scalar " << context << " " << name << " " << val << std::endl;
   // end OmnetDataOutput::OmnetOutputCallback::OutputSingleton
 }
+
 void
-OmnetDataOutput::OmnetOutputCallback::OutputSingleton(std::string key,
-                                                      std::string variable,
+OmnetDataOutput::OmnetOutputCallback::OutputSingleton(std::string context,
+                                                      std::string name,
                                                       std::string val)
 {
-  (*m_scalar) << "scalar " << key << " " << variable << " " << val << std::endl;
+	if (context == "")
+		context = ".";
+	if (name == "")
+		name = "\"\"";
+    (*m_scalar) << "scalar " << context << " " << name << " " << val << std::endl;
   // end OmnetDataOutput::OmnetOutputCallback::OutputSingleton
 }
+
 void
-OmnetDataOutput::OmnetOutputCallback::OutputSingleton(std::string key,
-                                                      std::string variable,
+OmnetDataOutput::OmnetOutputCallback::OutputSingleton(std::string context,
+                                                      std::string name,
                                                       Time val)
 {
-  (*m_scalar) << "scalar " << key << " " << variable << " " << val << std::endl;
+	if (context == "")
+		context = ".";
+	if (name == "")
+		name = "\"\"";
+    (*m_scalar) << "scalar " << context << " " << name << " " << val.GetTimeStep() << std::endl;
   // end OmnetDataOutput::OmnetOutputCallback::OutputSingleton
 }
--- a/src/contrib/stats/omnet-data-output.h	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/contrib/stats/omnet-data-output.h	Thu Nov 12 09:52:54 2009 +0100
@@ -45,24 +45,28 @@
     public:
       OmnetOutputCallback(std::ostream *scalar);
 
-      void OutputSingleton(std::string key,
-                           std::string variable,
+      void OutputStatistic(std::string context,
+                           std::string name,
+                           const StatisticalSummary *statSum);
+
+      void OutputSingleton(std::string context,
+                           std::string name,
                            int val);
 
-      void OutputSingleton(std::string key,
-                           std::string variable,
+      void OutputSingleton(std::string context,
+                           std::string name,
                            uint32_t val);
 
-      void OutputSingleton(std::string key,
-                           std::string variable,
+      void OutputSingleton(std::string context,
+                           std::string name,
                            double val);
 
-      void OutputSingleton(std::string key,
-                           std::string variable,
+      void OutputSingleton(std::string context,
+                           std::string name,
                            std::string val);
 
-      void OutputSingleton(std::string key,
-                           std::string variable,
+      void OutputSingleton(std::string context,
+                           std::string name,
                            Time val);
 
     private:
--- a/src/contrib/stats/sqlite-data-output.cc	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/contrib/stats/sqlite-data-output.cc	Thu Nov 12 09:52:54 2009 +0100
@@ -154,6 +154,25 @@
 }
 
 void
+SqliteDataOutput::SqliteOutputCallback::OutputStatistic(std::string key,
+                       std::string variable,
+                       const StatisticalSummary *statSum)
+{
+	OutputSingleton(key,variable+"-count", (double)statSum->getCount());
+	if (!isNaN(statSum->getSum()))
+		OutputSingleton(key,variable+"-total", statSum->getSum());
+	if (!isNaN(statSum->getMax()))
+		OutputSingleton(key,variable+"-max", statSum->getMax());
+	if (!isNaN(statSum->getMin()))
+		OutputSingleton(key,variable+"-min", statSum->getMin());
+	if (!isNaN(statSum->getSqrSum()))
+		OutputSingleton(key,variable+"-sqrsum", statSum->getSqrSum());
+	if (!isNaN(statSum->getStddev()))
+		OutputSingleton(key,variable+"-stddev", statSum->getStddev());
+}
+
+
+void
 SqliteDataOutput::SqliteOutputCallback::OutputSingleton(std::string key,
                                                         std::string variable,
                                                         int val)
--- a/src/contrib/stats/sqlite-data-output.h	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/contrib/stats/sqlite-data-output.h	Thu Nov 12 09:52:54 2009 +0100
@@ -48,6 +48,10 @@
     public:
       SqliteOutputCallback(Ptr<SqliteDataOutput> owner, std::string run);
 
+      void OutputStatistic(std::string key,
+                           std::string variable,
+                           const StatisticalSummary *statSum);
+
       void OutputSingleton(std::string key,
                            std::string variable,
                            int val);
--- a/src/contrib/stats/time-data-calculators.cc	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/contrib/stats/time-data-calculators.cc	Thu Nov 12 09:52:54 2009 +0100
@@ -70,12 +70,12 @@
 void
 TimeMinMaxAvgTotalCalculator::Output(DataOutputCallback &callback) const
 {
-  callback.OutputSingleton(m_key, "count", m_count);
+  callback.OutputSingleton(m_context, m_key + "-count", m_count);
   if (m_count > 0) {
-    callback.OutputSingleton(m_key, "total", m_total);
-    callback.OutputSingleton(m_key, "average", m_total/Scalar(m_count));
-    callback.OutputSingleton(m_key, "max", m_max);
-    callback.OutputSingleton(m_key, "min", m_min);
+    callback.OutputSingleton(m_context, m_key + "-total", m_total);
+    callback.OutputSingleton(m_context, m_key + "-average", m_total/Scalar(m_count));
+    callback.OutputSingleton(m_context, m_key + "-max", m_max);
+    callback.OutputSingleton(m_context, m_key + "-min", m_min);
   }
   // end TimeMinMaxAvgTotalCalculator::Output
 }
--- a/src/contrib/wscript	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/contrib/wscript	Thu Nov 12 09:52:54 2009 +0100
@@ -14,9 +14,11 @@
     conf.report_optional_feature("XmlIo", "XmlIo",
                                  conf.env['ENABLE_LIBXML2'],
                                  "library 'libxml-2.0 >= 2.7' not found")
-    conf.sub_config('stats')
+    conf.write_config_header('ns3/contrib-config.h', top=True)
 
-    conf.write_config_header('ns3/contrib-config.h', top=True)
+    conf.sub_config('stats')
+    conf.sub_config('net-anim')
+
 
 def build(bld):
     module = bld.create_ns3_module('contrib', ['simulator', 'common'])
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/object-ref-count.h	Thu Nov 12 09:52:54 2009 +0100
@@ -0,0 +1,120 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009 Mathieu Lacage
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@gmail.com>
+ */
+#ifndef OBJECT_REF_COUNT_H
+#define OBJECT_REF_COUNT_H
+
+#include "empty.h"
+
+namespace ns3 {
+
+/**
+ * This templated class provides the refcounting implementation
+ * for the ns3::Object class.
+ *
+ * The tricky aspect of the implementation of this class is that
+ * instead of storing a count directly, it keeps track of a pointer
+ * to a count to allow multiple instances of the class to share the
+ * same pointer/count. This is mainly used by the aggregation support
+ * of the ns3::Object class
+ */
+template <typename T, typename PARENT = empty>
+class ObjectRefCount : public PARENT
+{
+public:
+  ObjectRefCount ()
+    : m_count (new int (1))
+  {}
+  ObjectRefCount (const ObjectRefCount &o)
+    : m_count (new int (1))
+  {}
+  ObjectRefCount & operator = (const ObjectRefCount &o)
+  {
+    return *this;
+  }
+  ~ObjectRefCount () 
+  {
+    m_count = 0;
+  }
+
+  /**
+   * Get the reference count of the object.  Normally not needed; for language bindings.
+   */
+  int GetReferenceCount (void) const {
+    return *m_count;
+  }
+  /**
+   * Increment the reference count. This method should not be called
+   * by user code. Object instances are expected to be used in conjunction
+   * of the Ptr template which would make calling Ref unecessary and 
+   * dangerous.
+   */
+  inline void Ref (void) const
+    {
+      (*m_count)++;
+    }
+  /**
+   * Decrement the reference count. This method should not be called
+   * by user code. Object instances are expected to be used in conjunction
+   * of the Ptr template which would make calling Ref unecessary and 
+   * dangerous.
+   */
+  inline void Unref (void) const
+    {
+      (*m_count)--;
+      if ((*m_count) == 0)
+        {
+	  const_cast<ObjectRefCount<T,PARENT>*>(this)->DoDelete ();
+        }
+    }
+protected:
+  /**
+   * \param other another object
+   *
+   * This method makes this object and the input other object
+   * share the same reference count.
+   */
+  void ShareCount (ObjectRefCount *other)
+    {
+      (*m_count) += (*other->m_count);
+      delete other->m_count;
+      other->m_count = m_count;
+    }
+  /**
+   * Called just before deleting this object: when two
+   * objects share the same reference count, the user
+   * who is deleting them must be careful to delete the
+   * associated count only once and this is done by calling 
+   * this method to get a reference to the count and, then,
+   * calling delete on the count.
+   *
+   * \sa ns3::Object::DoDelete
+   */
+  int *PeekCountPtr (void) const
+    {
+      return m_count;
+    }
+private:
+  virtual void DoDelete (void) = 0;
+  mutable int *m_count;
+};
+
+} // namespace ns3
+
+#endif /* OBJECT_REF_COUNT_H */
--- a/src/core/object.cc	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/core/object.cc	Thu Nov 12 09:52:54 2009 +0100
@@ -28,6 +28,8 @@
 #include "string.h"
 #include <vector>
 #include <sstream>
+#include <stdlib.h>
+#include <string.h>
 
 NS_LOG_COMPONENT_DEFINE ("Object");
 
@@ -40,28 +42,23 @@
 NS_OBJECT_ENSURE_REGISTERED (Object);
 
 Object::AggregateIterator::AggregateIterator ()
-  : m_first (0),
+  : m_object (0),
     m_current (0)
 {}
 
 bool 
 Object::AggregateIterator::HasNext (void) const
 {
-  if (m_current != 0 && m_current->m_next != PeekPointer (m_first))
-    {
-      return true;
-    }
-  return false;
+  return m_current < m_object->m_aggregates->n;
 }
 Ptr<const Object> 
 Object::AggregateIterator::Next (void)
 {
-  m_current = m_current->m_next;
-  return m_current;
+  return m_object->m_aggregates->buffer[m_current];
 }
-Object::AggregateIterator::AggregateIterator (Ptr<const Object> first)
-  : m_first (first),
-    m_current (first)
+Object::AggregateIterator::AggregateIterator (Ptr<const Object> object)
+  : m_object (object),
+    m_current (0)
 {}
 
 
@@ -82,25 +79,45 @@
 
 
 Object::Object ()
-  : m_count (1),
-    m_tid (Object::GetTypeId ()),
+  : m_tid (Object::GetTypeId ()),
     m_disposed (false),
-    m_next (this)
-{}
+    m_aggregates ((struct Aggregates *)malloc (sizeof (struct Aggregates))),
+    m_getObjectCount (0)
+{
+  m_aggregates->n = 1;
+  m_aggregates->buffer[0] = this;
+}
 Object::~Object () 
 {
-  m_next = 0;
+  // remove this object from the aggregate list
+  uint32_t n = m_aggregates->n;
+  for (uint32_t i = 0; i < n; i++)
+    {
+      Object *current = m_aggregates->buffer[i];
+      if (current == this)
+        {
+          memmove (&m_aggregates->buffer[i], 
+                   &m_aggregates->buffer[i+1],
+                   sizeof (Object *)*(m_aggregates->n - (i+1)));
+          m_aggregates->n--;
+        }
+    }
+  // finally, if all objects have been removed from the list,
+  // delete the aggregate list
+  if (m_aggregates->n == 0)
+    {
+      free (m_aggregates);
+    }
+  m_aggregates = 0;
 }
 Object::Object (const Object &o)
-  : m_count (1),
-    m_tid (o.m_tid),
+  : m_tid (o.m_tid),
     m_disposed (false),
-    m_next (this)
-{}
-uint32_t
-Object::GetReferenceCount (void) const
+    m_aggregates ((struct Aggregates *)malloc (sizeof (struct Aggregates))),
+    m_getObjectCount (0)
 {
-  return m_count;
+  m_aggregates->n = 1;
+  m_aggregates->buffer[0] = this;
 }
 void
 Object::Construct (const AttributeList &attributes)
@@ -112,34 +129,58 @@
 Object::DoGetObject (TypeId tid) const
 {
   NS_ASSERT (CheckLoose ());
-  const Object *currentObject = this;
+
+  uint32_t n = m_aggregates->n;
   TypeId objectTid = Object::GetTypeId ();
-  do {
-    NS_ASSERT (currentObject != 0);
-    TypeId cur = currentObject->GetInstanceTypeId ();
-    while (cur != tid && cur != objectTid)
-      {
-        cur = cur.GetParent ();
-      }
-    if (cur == tid)
-      {
-        return const_cast<Object *> (currentObject);
-      }
-    currentObject = currentObject->m_next;
-  } while (currentObject != this);
+  for (uint32_t i = 0; i < n; i++)
+    {
+      Object *current = m_aggregates->buffer[i];
+      TypeId cur = current->GetInstanceTypeId ();
+      while (cur != tid && cur != objectTid)
+        {
+          cur = cur.GetParent ();
+        }
+      if (cur == tid)
+        {
+          // This is an attempt to 'cache' the result of this lookup.
+          // the idea is that if we perform a lookup for a TypeId on this object,
+          // we are likely to perform the same lookup later so, we make sure
+          // that the aggregate array is sorted by the number of accesses
+          // to each object.
+
+          // first, increment the access count
+          current->m_getObjectCount++;
+          // then, update the sort
+          UpdateSortedArray (m_aggregates, i);
+          // finally, return the match
+          return const_cast<Object *> (current);
+        }
+    }
   return 0;
 }
 void 
 Object::Dispose (void)
 {
-  Object *current = this;
-  do {
-    NS_ASSERT (current != 0);
-    NS_ASSERT (!current->m_disposed);
-    current->DoDispose ();
-    current->m_disposed = true;
-    current = current->m_next;
-  } while (current != this);
+  uint32_t n = m_aggregates->n;
+  for (uint32_t i = 0; i < n; i++)
+    {
+      Object *current = m_aggregates->buffer[i];
+      NS_ASSERT (!current->m_disposed);
+      current->DoDispose ();
+      current->m_disposed = true;
+    }
+}
+void
+Object::UpdateSortedArray (struct Aggregates *aggregates, uint32_t j) const
+{
+  while (j > 0 && 
+         aggregates->buffer[j]->m_getObjectCount > aggregates->buffer[j-1]->m_getObjectCount)
+    {
+      Object *tmp = aggregates->buffer[j-1];
+      aggregates->buffer[j-1] = aggregates->buffer[j];
+      aggregates->buffer[j] = tmp;
+      j--;
+    }
 }
 void 
 Object::AggregateObject (Ptr<Object> o)
@@ -157,20 +198,42 @@
     }
 
   Object *other = PeekPointer (o);
-  Object *next = m_next;
-  m_next = other->m_next;
-  other->m_next = next;
-  NS_ASSERT (CheckLoose ());
-  NS_ASSERT (o->CheckLoose ());
-  // call NotifyNewAggregate in the listed chain
-  Object *currentObject = this;
-  do 
+  // first create the new aggregate buffer.
+  uint32_t total = m_aggregates->n + other->m_aggregates->n;
+  struct Aggregates *aggregates = 
+    (struct Aggregates *)malloc (sizeof(struct Aggregates)+(total-1)*sizeof(Object*));
+  aggregates->n = total;
+  memcpy (&aggregates->buffer[0], 
+          &m_aggregates->buffer[0], 
+          m_aggregates->n*sizeof(Object*));
+  // append the other aggregates in the new buffer
+  for (uint32_t i = 0; i < other->m_aggregates->n; i++)
     {
-      // the NotifyNewAggregate of the current object implementation
-      // should be called on the next object in the linked chain
-      currentObject->NotifyNewAggregate ();
-      currentObject = currentObject->m_next;
-    } while (currentObject != this);
+      aggregates->buffer[m_aggregates->n+i] = other->m_aggregates->buffer[i];
+      UpdateSortedArray (aggregates, m_aggregates->n + i);
+    }
+
+  // free both aggregate buffers
+  free (m_aggregates);
+  free (other->m_aggregates);
+
+  // Then, assign that buffer to every object
+  uint32_t n = aggregates->n;
+  for (uint32_t i = 0; i < n; i++)
+    {
+      Object *current = aggregates->buffer[i];
+      current->m_aggregates = aggregates;
+    }
+
+  // share the counts
+  ShareCount (other);
+
+  // Finally, call NotifyNewAggregate in the listed chain
+  for (uint32_t i = 0; i < n; i++)
+    {
+      Object *current = m_aggregates->buffer[i];
+      current->NotifyNewAggregate ();
+    }
 }
 /**
  * This function must be implemented in the stack that needs to notify
@@ -205,7 +268,7 @@
 bool 
 Object::Check (void) const
 {
-  return (m_count > 0);
+  return (GetReferenceCount () > 0);
 }
 
 /* In some cases, when an event is scheduled against a subclass of
@@ -219,54 +282,43 @@
 Object::CheckLoose (void) const
 {
   uint32_t refcount = 0;
-  const Object *current = this;
-  do
+  uint32_t n = m_aggregates->n;
+  for (uint32_t i = 0; i < n; i++)
     {
-      refcount += current->m_count;
-      current = current->m_next;
+      Object *current = m_aggregates->buffer[i];
+      refcount += current->GetReferenceCount ();
     }
-  while (current != this);
-
   return (refcount > 0);
 }
-
 void
-Object::MaybeDelete (void) const
+Object::DoDelete (void)
 {
-  // First, check if any of the attached
-  // Object has a non-zero count.
-  const Object *current = this;
-  do {
-    NS_ASSERT (current != 0);
-    if (current->m_count != 0)
-      {
-        return;
-      }
-    current = current->m_next;
-  } while (current != this);
-
+  uint32_t n = m_aggregates->n;
   // Ensure we are disposed.
-  Object *tmp = const_cast<Object *> (this);
-  const Object *end = this;
-  do {
-    NS_ASSERT (current != 0);
-    Object *next = tmp->m_next;
-    if (!tmp->m_disposed)
-      {
-        tmp->DoDispose ();
-      }
-    tmp = next;
-  } while (tmp != end);
+  for (uint32_t i = 0; i < n; i++)
+    {
+      Object *current = m_aggregates->buffer[i];
+      if (!current->m_disposed)
+        {
+          current->DoDispose ();
+        }
+    }
+
+  int *count = PeekCountPtr ();
 
-  // all attached objects have a zero count so, 
-  // we can delete all attached objects.
-  current = this;
-  do {
-    NS_ASSERT (current != 0);
-    Object *next = current->m_next;
-    delete current;
-    current = next;
-  } while (current != end);
+  // Now, actually delete all objects
+  struct Aggregates *aggregates = m_aggregates;
+  for (uint32_t i = 0; i < n; i++)
+    {
+      // There is a trick here: each time we call delete below,
+      // the deleted object is removed from the aggregate buffer
+      // in the destructor so, the index of the next element to 
+      // lookup is always zero
+      Object *current = aggregates->buffer[0];
+      delete current;
+    }
+
+  delete count;
 }
 } // namespace ns3
 
--- a/src/core/object.h	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/core/object.h	Thu Nov 12 09:52:54 2009 +0100
@@ -28,6 +28,7 @@
 #include "attribute.h"
 #include "object-base.h"
 #include "attribute-list.h"
+#include "object-ref-count.h"
 
 
 namespace ns3 {
@@ -55,7 +56,7 @@
  * invoked from the Object::Unref method before destroying the object, even if the user 
  * did not call Object::Dispose directly.
  */
-class Object : public ObjectBase
+class Object : public ObjectRefCount<Object,ObjectBase>
 {
 public:
   static TypeId GetTypeId (void);
@@ -85,9 +86,9 @@
     Ptr<const Object> Next (void);
   private:
     friend class Object;
-    AggregateIterator (Ptr<const Object> first);
-    Ptr<const Object> m_first;
-    Ptr<const Object> m_current;
+    AggregateIterator (Ptr<const Object> object);
+    Ptr<const Object> m_object;
+    uint32_t m_current;
   };
 
   Object ();
@@ -99,30 +100,10 @@
   virtual TypeId GetInstanceTypeId (void) const;
 
   /**
-   * Increment the reference count. This method should not be called
-   * by user code. Object instances are expected to be used in conjunction
-   * of the Ptr template which would make calling Ref unecessary and 
-   * dangerous.
-   */
-  inline void Ref (void) const;
-  /**
-   * Decrement the reference count. This method should not be called
-   * by user code. Object instances are expected to be used in conjunction
-   * of the Ptr template which would make calling Ref unecessary and 
-   * dangerous.
-   */
-  inline void Unref (void) const;
-
-  /**
-   * Get the reference count of the object.  Normally not needed; for language bindings.
-   */
-  uint32_t GetReferenceCount (void) const;
-
-  /**
    * \returns a pointer to the requested interface or zero if it could not be found.
    */
   template <typename T>
-  Ptr<T> GetObject (void) const;
+  inline Ptr<T> GetObject (void) const;
   /**
    * \param tid the interface id of the requested interface
    * \returns a pointer to the requested interface or zero if it could not be found.
@@ -215,17 +196,25 @@
   friend class ObjectFactory;
   friend class AggregateIterator;
 
+  /**
+   * This data structure uses a classic C-style trick to 
+   * hold an array of variable size without performing
+   * two memory allocations: the declaration of the structure
+   * declares a one-element array but when we allocate
+   * memory for this struct, we effectively allocate a larger
+   * chunk of memory than the struct to allow space for a larger
+   * variable sized buffer whose size is indicated by the element
+   * 'n'
+   */
+  struct Aggregates {
+    uint32_t n;
+    Object *buffer[1];
+  };
+
   Ptr<Object> DoGetObject (TypeId tid) const;
   bool Check (void) const;
   bool CheckLoose (void) const;
   /**
-   * Attempt to delete this object. This method iterates
-   * over all aggregated objects to check if they all 
-   * have a zero refcount. If yes, the object and all
-   * its aggregates are deleted. If not, nothing is done.
-   */
-  void MaybeDelete (void) const;
-  /**
    * \param tid an TypeId
    *
    * Invoked from ns3::CreateObject only.
@@ -243,14 +232,15 @@
    */
   void Construct (const AttributeList &attributes);
 
+  void UpdateSortedArray (struct Aggregates *aggregates, uint32_t i) const;
   /**
-   * The reference count for this object. Each aggregate
-   * has an individual reference count. When the global
-   * reference count (the sum of all reference counts) 
-   * reaches zero, the object and all its aggregates is 
-   * deleted.
+   * Attempt to delete this object. This method iterates
+   * over all aggregated objects to check if they all 
+   * have a zero refcount. If yes, the object and all
+   * its aggregates are deleted. If not, nothing is done.
    */
-  mutable uint32_t m_count;
+  virtual void DoDelete (void);
+
   /**
    * Identifies the type of this object instance.
    */
@@ -261,13 +251,19 @@
    */
   bool m_disposed;
   /**
-   * A pointer to the next aggregate object. This is a circular
-   * linked list of aggregated objects: the last one points
-   * back to the first one. If an object is not aggregated to
-   * any other object, the value of this field is equal to the
-   * value of the 'this' pointer.
+   * a pointer to an array of 'aggregates'. i.e., a pointer to
+   * each object aggregated to this object is stored in this 
+   * array. The array is shared by all aggregated objects
+   * so the size of the array is indirectly a reference count.
    */
-  Object *m_next;
+  struct Aggregates * m_aggregates;
+  /**
+   * Indicates the number of times the object was accessed with a
+   * call to GetObject. This integer is used to implement a
+   * heuristic to sort the array of aggregates to put at the start
+   * of the array the most-frequently accessed elements.
+   */
+  uint32_t m_getObjectCount;
 };
 
 /**
@@ -340,26 +336,15 @@
  *   The Object implementation which depends on templates
  *************************************************************************/
 
-void
-Object::Ref (void) const
-{
-  m_count++;
-}
-void
-Object::Unref (void) const
-{
-  NS_ASSERT (Check ());
-  m_count--;
-  if (m_count == 0)
-    {
-      MaybeDelete ();
-    }
-}
-
 template <typename T>
 Ptr<T> 
 Object::GetObject () const
 {
+  T *result = dynamic_cast<T *> (m_aggregates->buffer[0]);
+  if (result != 0)
+    {
+      return Ptr<T> (result);
+    }
   Ptr<Object> found = DoGetObject (T::GetTypeId ());
   if (found != 0)
     {
--- a/src/core/system-thread.h	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/core/system-thread.h	Thu Nov 12 09:52:54 2009 +0100
@@ -72,12 +72,20 @@
    * is asking the SystemThread to call object->MyMethod () in a new thread
    * of execution.
    *
-   * Remember that if you are invoking a callback on an object that is
-   * managed by a smart pointer, you need to call PeekPointer.
+   * If starting a thread in your currently executing object, you can use the
+   * "this" pointer:
+   *
+   *   Ptr<SystemThread> st = Create<SystemThread> (
+   *     MakeCallback (&MyClass::MyMethod, this));
+   *   st->Start ();
+   *
+   * Object lifetime is always an issue with threads, so it is common to use
+   * smart pointers.  If you are spinning up a thread in an object that is 
+   * managed by a smart pointer, you can use that pointer directly:
    *
    *   Ptr<MyClass> myPtr = Create<MyClass> ();
    *   Ptr<SystemThread> st = Create<SystemThread> (
-   *     MakeCallback (&MyClass::MyMethod, PeekPointer (myPtr)));
+   *     MakeCallback (&MyClass::MyMethod, myPtr));
    *   st->Start ();
    *
    * Just like any thread, you can synchronize with its termination.  The 
--- a/src/core/test.cc	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/core/test.cc	Thu Nov 12 09:52:54 2009 +0100
@@ -87,6 +87,7 @@
     m_continueOnFailure (false), 
     m_detailsReported (false), 
     m_basedir ("invalid"), 
+    m_tempdir ("invalid"), 
     m_ofs (0), 
     m_error (false)
 {
@@ -203,7 +204,18 @@
 void 
 TestCase::SetBaseDir (std::string basedir)
 {
-  m_basedir = basedir;
+  //
+  // C and C++ allow one to use forward slashes even on systems where the 
+  // separator is actually a backslash.
+  //
+  if (basedir[basedir.length () - 1] != '/')
+    {
+      m_basedir = basedir + "/";
+    }
+  else
+    {
+      m_basedir = basedir;
+    }
 }
 
 std::string 
@@ -212,13 +224,52 @@
   return m_basedir;
 }
 
+void 
+TestCase::SetTempDir (std::string tempdir)
+{
+  //
+  // C and C++ allow one to use forward slashes even on systems where the 
+  // separator is actually a backslash.
+  //
+  if (tempdir[tempdir.length () - 1] != '/')
+    {
+      m_tempdir = tempdir + "/";
+    }
+  else
+    {
+      m_tempdir = tempdir;
+    }
+}
+
+std::string 
+TestCase::GetTempDir (void)
+{
+  return m_tempdir;
+}
+
 std::string 
 TestCase::GetSourceDir (std::string file)
 {
+  //
+  // The <file> parameter is actually going to be __FILE__ which may have 
+  // backslashes in it on win32 systems.  For example,
+  //
+  //   ..\src\common\pcap-file-test-suite.cc  (win32)
+  //
+  // or
+  //
+  //   ../src/common/pcap-file-test-suite.cc  (grown-up systems)
+  //
+#ifdef WIN32
+  std::string::size_type relPathBegin = file.find_first_of ("\\");
+  std::string::size_type relPathEnd = file.find_last_of ("\\");
+#else
   std::string::size_type relPathBegin = file.find_first_of ("/");
-  NS_ABORT_MSG_IF (relPathBegin == std::string::npos, "TestCase::GetSrouceDir(): Internal Error");
   std::string::size_type relPathEnd = file.find_last_of ("/");
-  NS_ABORT_MSG_IF (relPathEnd == std::string::npos, "TestCase::GetSrouceDir(): Internal Error");
+#endif
+
+  NS_ABORT_MSG_IF (relPathBegin == std::string::npos, "TestCase::GetSourceDir(): Internal Error");
+  NS_ABORT_MSG_IF (relPathEnd == std::string::npos, "TestCase::GetSourceDir(): Internal Error");
 
   return GetBaseDir () + file.substr (relPathBegin, relPathEnd + 1 - relPathBegin);
 }
@@ -353,6 +404,7 @@
   : m_name (name), 
     m_verbose (false), 
     m_basedir ("invalid"), 
+    m_tempdir ("invalid"), 
     m_ofs (0), 
     m_error (false), 
     m_type (type)
@@ -476,7 +528,18 @@
 void 
 TestSuite::SetBaseDir (std::string basedir)
 {
-  m_basedir = basedir;
+  //
+  // C and C++ allow one to use forward slashes even on systems where the 
+  // separator is actually a backslash.
+  //
+  if (basedir[basedir.length () - 1] != '/')
+    {
+      m_basedir = basedir + "/";
+    }
+  else
+    {
+      m_basedir = basedir;
+    }
 }
 
 std::string 
@@ -486,6 +549,29 @@
 }
 
 void 
+TestSuite::SetTempDir (std::string tempdir)
+{
+  //
+  // C and C++ allow one to use forward slashes even on systems where the 
+  // separator is actually a backslash.
+  //
+  if (tempdir[tempdir.length () - 1] != '/')
+    {
+      m_tempdir = tempdir + "/";
+    }
+  else
+    {
+      m_tempdir = tempdir;
+    }
+}
+
+std::string 
+TestSuite::GetTempDir (void)
+{
+  return m_tempdir;
+}
+
+void 
 TestSuite::SetStream (std::ofstream *ofs)
 {
   m_ofs = ofs;
@@ -589,6 +675,7 @@
       (*i)->SetVerbose (m_verbose);
       (*i)->SetContinueOnFailure (m_continueOnFailure);
       (*i)->SetBaseDir (m_basedir);
+      (*i)->SetTempDir (m_tempdir);
       (*i)->SetStream (m_ofs);
 
       //
--- a/src/core/test.h	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/core/test.h	Thu Nov 12 09:52:54 2009 +0100
@@ -662,6 +662,16 @@
    */
   std::string GetBaseDir (void);
 
+  /**
+   * \brief Set the temporary file directory (where to write temporary files).
+   */
+  void SetTempDir (std::string dir);
+
+  /**
+   * \brief Get the temporary file directory .
+   */
+  std::string GetTempDir (void);
+
 /**
  * \brief Get the source directory of the current source file.
  *
@@ -830,6 +840,7 @@
   bool m_continueOnFailure;
   bool m_detailsReported;
   std::string m_basedir;
+  std::string m_tempdir;
   std::ofstream *m_ofs;
   bool m_error;
 };
@@ -945,6 +956,16 @@
   std::string GetBaseDir (void);
 
   /**
+   * \brief Set the temporary file directory (where to write temporary files).
+   */
+  void SetTempDir (std::string dir);
+
+  /**
+   * \brief Get the temporary file directory.
+   */
+  std::string GetTempDir (void);
+
+  /**
    * \brief Set the stream to which status and result messages will be written.
    *
    * We really don't want to have to pass an ofstream around to every function
@@ -1064,6 +1085,7 @@
   bool m_verbose;
   bool m_continueOnFailure;
   std::string m_basedir;
+  std::string m_tempdir;
   std::ofstream *m_ofs;
   bool m_error;
   TestType m_type;
--- a/src/core/wscript	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/core/wscript	Thu Nov 12 09:52:54 2009 +0100
@@ -126,6 +126,7 @@
         'abort.h',
         'names.h',
         'vector.h',
+        'object-ref-count.h',
         ]
 
     if sys.platform == 'win32':
--- a/src/devices/mesh/dot11s/dot11s-test-suite.cc	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/devices/mesh/dot11s/dot11s-test-suite.cc	Thu Nov 12 09:52:54 2009 +0100
@@ -174,9 +174,9 @@
 {
   for (std::vector<Mac48Address>::const_iterator i = precursors.begin (); i != precursors.end (); i++)
     {
-      table->AddPrecursor (dst, iface, *i);
+      table->AddPrecursor (dst, iface, *i, Seconds (100));
       // Check that duplicates are filtered
-      table->AddPrecursor (dst, iface, *i);
+      table->AddPrecursor (dst, iface, *i, Seconds (100));
     }
 }
 
--- a/src/devices/mesh/dot11s/hwmp-protocol.cc	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/devices/mesh/dot11s/hwmp-protocol.cc	Thu Nov 12 09:52:54 2009 +0100
@@ -401,6 +401,7 @@
   //acceptance cretirea:
   std::map<Mac48Address, std::pair<uint32_t, uint32_t> >::const_iterator i = m_hwmpSeqnoMetricDatabase.find (
       preq.GetOriginatorAddress ());
+  bool freshInfo (true);
   if (i != m_hwmpSeqnoMetricDatabase.end ())
     {
       if ((int32_t)(i->second.first - preq.GetOriginatorSeqNumber ())  > 0)
@@ -409,21 +410,25 @@
         }
       if (i->second.first == preq.GetOriginatorSeqNumber ())
         {
+          freshInfo = false;
           if (i->second.second <= preq.GetMetric ())
             {
               return;
             }
         }
     }
-  m_hwmpSeqnoMetricDatabase[preq.GetOriginatorAddress ()] = std::make_pair (preq.GetOriginatorSeqNumber (), preq.GetMetric ());
-
+  m_hwmpSeqnoMetricDatabase[preq.GetOriginatorAddress ()] =
+    std::make_pair (preq.GetOriginatorSeqNumber (), preq.GetMetric ());
   NS_LOG_DEBUG("I am " << GetAddress () << "Accepted preq from address" << from << ", preq:" << preq);
   std::vector<Ptr<DestinationAddressUnit> > destinations = preq.GetDestinationList ();
   //Add reactive path to originator:
   if (
-      ((m_rtable->LookupReactive (preq.GetOriginatorAddress ())).retransmitter == Mac48Address::GetBroadcast ()) ||
-      ((m_rtable->LookupReactive (preq.GetOriginatorAddress ())).metric > preq.GetMetric ())
+      (freshInfo) ||
+      (
+        (m_rtable->LookupReactive (preq.GetOriginatorAddress ()).retransmitter == Mac48Address::GetBroadcast ()) ||
+        (m_rtable->LookupReactive (preq.GetOriginatorAddress ()).metric > preq.GetMetric ())
       )
+     )
     {
       m_rtable->AddReactivePath (
           preq.GetOriginatorAddress (),
@@ -432,13 +437,12 @@
           preq.GetMetric (),
           MicroSeconds (preq.GetLifetime () * 1024),
           preq.GetOriginatorSeqNumber ()
-          );
+        );
       ReactivePathResolved (preq.GetOriginatorAddress ());
     }
-  //Add reactive path for precursor:
   if (
-      ((m_rtable->LookupReactive (fromMp)).retransmitter == Mac48Address::GetBroadcast ()) ||
-      ((m_rtable->LookupReactive (fromMp)).metric > preq.GetMetric ())
+      (m_rtable->LookupReactive (fromMp).retransmitter == Mac48Address::GetBroadcast ()) ||
+      (m_rtable->LookupReactive (fromMp).metric > metric)
       )
     {
       m_rtable->AddReactivePath (
@@ -477,15 +481,6 @@
                   preq.GetOriginatorSeqNumber ()
                   );
               ProactivePathResolved ();
-              m_rtable->AddReactivePath (
-                  preq.GetOriginatorAddress (),
-                  from,
-                  interface,
-                  preq.GetMetric (),
-                  MicroSeconds (preq.GetLifetime () * 1024),
-                  preq.GetOriginatorSeqNumber ()
-                  );
-              ReactivePathResolved (preq.GetOriginatorAddress ());
             }
           if (!preq.IsNeedNotPrep ())
             {
@@ -493,7 +488,7 @@
                   GetAddress (),
                   preq.GetOriginatorAddress (),
                   from,
-                  preq.GetMetric (),
+                  (uint32_t)0,
                   preq.GetOriginatorSeqNumber (),
                   GetNextHwmpSeqno (),
                   preq.GetLifetime (),
@@ -523,9 +518,6 @@
       if ((! ((*i)->IsDo ())) && (result.retransmitter != Mac48Address::GetBroadcast ()))
         {
           //have a valid information and can answer
-          //!NB: If there is information from peer - set lifetime as
-          //we have got from PREQ, and set the rest lifetime of the
-          //route if the information is correct
           uint32_t lifetime = result.lifetime.GetMicroSeconds () / 1024;
           if ((lifetime > 0) && ((int32_t)(result.seqnum - (*i)->GetDestSeqNumber ()) >= 0))
             {
@@ -539,6 +531,8 @@
                   lifetime,
                   interface
                   );
+              m_rtable->AddPrecursor ((*i)->GetDestinationAddress (), interface, from,
+                  MicroSeconds (preq.GetLifetime () * 1024));
               if ((*i)->IsRf ())
                 {
                   (*i)->SetFlags (true, false, (*i)->IsUsn ()); //DO = 1, RF = 0
@@ -570,38 +564,52 @@
   //acceptance cretirea:
   std::map<Mac48Address, std::pair<uint32_t, uint32_t> >::const_iterator i = m_hwmpSeqnoMetricDatabase.find (
       prep.GetOriginatorAddress ());
-  if ((i != m_hwmpSeqnoMetricDatabase.end ()) && ((int32_t)(i->second.first - prep.GetOriginatorSeqNumber ()) > 0))
+  bool freshInfo (true);
+  if (i != m_hwmpSeqnoMetricDatabase.end ())
     {
-      return;
+      if ((int32_t)(i->second.first - prep.GetOriginatorSeqNumber ()) > 0)
+        {
+          return;
+        }
+      if (i->second.first == prep.GetOriginatorSeqNumber ())
+        {
+          freshInfo = false;
+        }
     }
   m_hwmpSeqnoMetricDatabase[prep.GetOriginatorAddress ()] = std::make_pair (prep.GetOriginatorSeqNumber (), prep.GetMetric ());
   //update routing info
   //Now add a path to destination and add precursor to source
   NS_LOG_DEBUG ("I am " << GetAddress () << ", received prep from " << prep.GetOriginatorAddress () << ", receiver was:" << from);
   HwmpRtable::LookupResult result = m_rtable->LookupReactive (prep.GetDestinationAddress ());
-  //Add a reactive path only if it is better than existing:
+  //Add a reactive path only if seqno is fresher or it improves the
+  //metric
   if (
-      ((m_rtable->LookupReactive (prep.GetOriginatorAddress ())).retransmitter == Mac48Address::GetBroadcast ()) ||
-      ((m_rtable->LookupReactive (prep.GetOriginatorAddress ())).metric > prep.GetMetric ())
+      (freshInfo) ||
+      (
+       ((m_rtable->LookupReactive (prep.GetOriginatorAddress ())).retransmitter == Mac48Address::GetBroadcast ()) ||
+       ((m_rtable->LookupReactive (prep.GetOriginatorAddress ())).metric > prep.GetMetric ())
       )
+     )
     {
       m_rtable->AddReactivePath (
           prep.GetOriginatorAddress (),
           from,
           interface,
           prep.GetMetric (),
-          MicroSeconds(prep.GetLifetime () * 1024),
+          MicroSeconds (prep.GetLifetime () * 1024),
           prep.GetOriginatorSeqNumber ());
-      m_rtable->AddPrecursor (prep.GetDestinationAddress (), interface, from);
+      m_rtable->AddPrecursor (prep.GetDestinationAddress (), interface, from,
+          MicroSeconds (prep.GetLifetime () * 1024));
       if (result.retransmitter != Mac48Address::GetBroadcast ())
         {
-          m_rtable->AddPrecursor (prep.GetOriginatorAddress (), interface, result.retransmitter);
+          m_rtable->AddPrecursor (prep.GetOriginatorAddress (), interface, result.retransmitter,
+              result.lifetime);
         }
       ReactivePathResolved (prep.GetOriginatorAddress ());
     }
   if (
       ((m_rtable->LookupReactive (fromMp)).retransmitter == Mac48Address::GetBroadcast ()) ||
-      ((m_rtable->LookupReactive (fromMp)).metric > prep.GetMetric ())
+      ((m_rtable->LookupReactive (fromMp)).metric > metric)
       )
     {
       m_rtable->AddReactivePath (
@@ -669,7 +677,7 @@
   prep.SetDestinationAddress (dst);
   prep.SetDestinationSeqNumber (destinationSN);
   prep.SetLifetime (lifetime);
-  prep.SetMetric (0);
+  prep.SetMetric (initMetric);
   prep.SetOriginatorAddress (src);
   prep.SetOriginatorSeqNumber (originatorDsn);
   HwmpProtocolMacMap::const_iterator prep_sender = m_interfaces.find (interface);
--- a/src/devices/mesh/dot11s/hwmp-rtable.cc	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/devices/mesh/dot11s/hwmp-rtable.cc	Thu Nov 12 09:52:54 2009 +0100
@@ -84,11 +84,12 @@
 }
 void
 HwmpRtable::AddPrecursor (Mac48Address destination, uint32_t precursorInterface,
-    Mac48Address precursorAddress)
+    Mac48Address precursorAddress, Time lifetime)
 {
-  std::pair<uint32_t, Mac48Address> precursor;
-  precursor.first = precursorInterface;
-  precursor.second = precursorAddress;
+  Precursor precursor;
+  precursor.interface = precursorInterface;
+  precursor.address = precursorAddress;
+  precursor.whenExpire = Simulator::Now () + lifetime;
   std::map<Mac48Address, ReactiveRoute>::iterator i = m_routes.find (destination);
   if (i != m_routes.end ())
     {
@@ -97,9 +98,10 @@
         {
           //NB: Only one active route may exist, so do not check
           //interface ID, just address
-          if (i->second.precursors[j].second == precursorAddress)
+          if (i->second.precursors[j].address == precursorAddress)
             {
               should_add = false;
+              i->second.precursors[j].whenExpire = precursor.whenExpire;
               break;
             }
         }
@@ -108,17 +110,6 @@
           i->second.precursors.push_back (precursor);
         }
     }
-  if (m_root.root == destination)
-    {
-      for (unsigned int j = 0; j < m_root.precursors.size (); j++)
-        {
-          if (m_root.precursors[j].second == precursorAddress)
-            {
-              return;
-            }
-        }
-    }
-  m_root.precursors.push_back (precursor);
 }
 void
 HwmpRtable::DeleteProactivePath ()
@@ -221,27 +212,12 @@
   std::map<Mac48Address, ReactiveRoute>::iterator route = m_routes.find (destination);
   if (route != m_routes.end ())
     {
-      for (unsigned int i = 0; i < route->second.precursors.size (); i++)
-        {
-          retval.push_back (route->second.precursors[i]);
-        }
-    }
-  if (m_root.root == destination)
-    {
-      for (unsigned int i = 0; i < m_root.precursors.size (); i++)
+      for (std::vector<Precursor>::const_iterator i = route->second.precursors.begin ();
+          i != route->second.precursors.end (); i++)
         {
-          bool should_add = true;
-          for (unsigned int j = 0; j < retval.size (); j++)
+          if (i->whenExpire > Simulator::Now ())
             {
-              if (retval[j].second == m_root.precursors[i].second)
-                {
-                  should_add = false;
-                  break;
-                }
-            }
-          if (should_add)
-            {
-              retval.push_back (m_root.precursors[i]);
+              retval.push_back (std::make_pair(i->interface, i->address));
             }
         }
     }
--- a/src/devices/mesh/dot11s/hwmp-rtable.h	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/devices/mesh/dot11s/hwmp-rtable.h	Thu Nov 12 09:52:54 2009 +0100
@@ -85,7 +85,7 @@
     Time  lifetime,
     uint32_t seqnum
   );
-  void AddPrecursor (Mac48Address destination, uint32_t precursorInterface, Mac48Address precursorAddress);
+  void AddPrecursor (Mac48Address destination, uint32_t precursorInterface, Mac48Address precursorAddress, Time lifetime);
   PrecursorList GetPrecursors (Mac48Address destination);
   void DeleteProactivePath ();
   void DeleteProactivePath (Mac48Address root);
@@ -109,6 +109,12 @@
 
 private:
   /// Route found in reactive mode
+  struct Precursor
+  {
+    Mac48Address address;
+    uint32_t interface;
+    Time whenExpire;
+  };
   struct ReactiveRoute
   {
     Mac48Address retransmitter;
@@ -116,7 +122,7 @@
     uint32_t metric;
     Time whenExpire;
     uint32_t seqnum;
-    std::vector<std::pair<uint32_t, Mac48Address> > precursors;
+    std::vector<Precursor> precursors;
   };
   /// Route fond in proactive mode
   struct ProactiveRoute
@@ -127,7 +133,7 @@
     uint32_t metric;
     Time whenExpire;
     uint32_t seqnum;
-    std::vector<std::pair<uint32_t, Mac48Address> > precursors;
+    std::vector<Precursor> precursors;
   };
 
   /// List of routes
--- a/src/devices/mesh/dot11s/ie-dot11s-prep.cc	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/devices/mesh/dot11s/ie-dot11s-prep.cc	Thu Nov 12 09:52:54 2009 +0100
@@ -135,6 +135,7 @@
 IePrep::DecrementTtl ()
 {
   m_ttl--;
+  m_hopcount ++;
 }
 
 void
--- a/src/devices/mesh/dot11s/ie-dot11s-preq.cc	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/devices/mesh/dot11s/ie-dot11s-preq.cc	Thu Nov 12 09:52:54 2009 +0100
@@ -317,17 +317,17 @@
 IePreq::Print (std::ostream &os) const
 {
   os << std::endl << "<information_element id=" << ElementId () << ">" << std::endl;
-  os << " originator address  = " << m_originatorAddress << "std::endl";
-  os << " TTL                 = " << (uint16_t) m_ttl << "std::endl";
-  os << " hop count           = " << (uint16_t) m_hopCount << "std::endl";
-  os << " metric              = " << m_metric << "std::endl";
-  os << " seqno               = " << m_originatorSeqNumber << "std::endl";
-  os << " lifetime            = " << m_lifetime << "std::endl";
-  os << " preq ID             = " << m_preqId << "std::endl";
-  os << " Destinations are:std::endl";
+  os << " originator address  = " << m_originatorAddress << std::endl;
+  os << " TTL                 = " << (uint16_t) m_ttl << std::endl;
+  os << " hop count           = " << (uint16_t) m_hopCount << std::endl;
+  os << " metric              = " << m_metric << std::endl;
+  os << " seqno               = " << m_originatorSeqNumber << std::endl;
+  os << " lifetime            = " << m_lifetime << std::endl;
+  os << " preq ID             = " << m_preqId << std::endl;
+  os << " Destinations are:" << std::endl;
   for (int j = 0; j < m_destCount; j++)
     {
-      os << "    " << m_destinations[j]->GetDestinationAddress () << "std::endl";
+      os << "    " << m_destinations[j]->GetDestinationAddress () << std::endl;
     }
   os << "</information_element>" << std::endl;
 }
--- a/src/devices/mesh/dot11s/ie-dot11s-rann.cc	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/devices/mesh/dot11s/ie-dot11s-rann.cc	Thu Nov 12 09:52:54 2009 +0100
@@ -152,12 +152,12 @@
 IeRann::Print (std::ostream &os) const
 {
   os << std::endl << "<information_element id=" << ElementId () << ">" << std::endl;
-  os << "  flags              = " << (int) m_flags << "std::endl";
-  os << "  hop count          = " << (int) m_hopcount << "std::endl";
-  os << "  TTL                = " << (int) m_ttl << "std::endl";
-  os << "  originator address = " << m_originatorAddress << "std::endl";
-  os << "  dst seq. number    = " << m_destSeqNumber << "std::endl";
-  os << "  metric             = " << m_metric << "std::endl";
+  os << "  flags              = " << (int) m_flags << std::endl;
+  os << "  hop count          = " << (int) m_hopcount << std::endl;
+  os << "  TTL                = " << (int) m_ttl << std::endl;
+  os << "  originator address = " << m_originatorAddress << std::endl;
+  os << "  dst seq. number    = " << m_destSeqNumber << std::endl;
+  os << "  metric             = " << m_metric << std::endl;
   os << "</information_element>" << std::endl;
 }
 
--- a/src/devices/mesh/dot11s/peer-link-frame.cc	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/devices/mesh/dot11s/peer-link-frame.cc	Thu Nov 12 09:52:54 2009 +0100
@@ -69,7 +69,7 @@
     }
 }
 PeerLinkFrameStart::PlinkFrameStartFields
-PeerLinkFrameStart::GetFields ()
+PeerLinkFrameStart::GetFields () const
 {
   PlinkFrameStartFields retval;
   //TODO: protocol version:
--- a/src/devices/mesh/dot11s/peer-link-frame.h	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/devices/mesh/dot11s/peer-link-frame.h	Thu Nov 12 09:52:54 2009 +0100
@@ -62,7 +62,7 @@
   //action header knows about subtype
   void SetPlinkFrameSubtype (uint8_t subtype);
   void SetPlinkFrameStart (PlinkFrameStartFields);
-  PlinkFrameStartFields GetFields ();
+  PlinkFrameStartFields GetFields () const;
   /** \name Inherited from header:
    * \{
    */
--- a/src/devices/mesh/wifi-information-element-vector.cc	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/devices/mesh/wifi-information-element-vector.cc	Thu Nov 12 09:52:54 2009 +0100
@@ -58,7 +58,8 @@
 WifiInformationElementVector::GetTypeId ()
 {
   static TypeId tid = TypeId ("ns3::WifiInformationElementVector")
-                      .SetParent<Header> ();
+                      .SetParent<Header> ()
+                      .AddConstructor<WifiInformationElementVector> ();
   return tid;
 }
 TypeId
--- a/src/devices/point-to-point/point-to-point-net-device.cc	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/devices/point-to-point/point-to-point-net-device.cc	Thu Nov 12 09:52:54 2009 +0100
@@ -173,8 +173,8 @@
 PointToPointNetDevice::AddHeader(Ptr<Packet> p, uint16_t protocolNumber)
 {
   NS_LOG_FUNCTION_NOARGS ();
-  NS_ASSERT_MSG (protocolNumber == 0x800, "PointToPointNetDevice::AddHeader(): protocolNumber must be 0x800");
   PppHeader ppp;
+  ppp.SetProtocol(EtherToPpp(protocolNumber));
   p->AddHeader (ppp);
 }
 
@@ -184,7 +184,7 @@
   NS_LOG_FUNCTION_NOARGS ();
   PppHeader ppp;
   p->RemoveHeader (ppp);
-  param = 0x800;
+  param = PppToEther(ppp.GetProtocol());
   return true;
 }
 
@@ -655,5 +655,29 @@
   return m_mtu;
 }
 
+  uint16_t
+PointToPointNetDevice::PppToEther(uint16_t proto)
+{
+  switch(proto)
+    {
+      case 0x0021: return 0x0800; //IPv4
+      case 0x0057: return 0x86DD; //IPv6
+      default: NS_ASSERT_MSG(false, "PPP Protocol number not defined!");
+    }
+  return 0;
+}
+
+  uint16_t
+PointToPointNetDevice::EtherToPpp(uint16_t proto)
+{
+  switch(proto)
+    {
+      case 0x0800: return 0x0021; //IPv4
+      case 0x86DD: return 0x0057; //IPv6
+      default: NS_ASSERT_MSG(false, "PPP Protocol number not defined!");
+    }
+  return 0;
+}
+
 
 } // namespace ns3
--- a/src/devices/point-to-point/point-to-point-net-device.h	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/devices/point-to-point/point-to-point-net-device.h	Thu Nov 12 09:52:54 2009 +0100
@@ -548,6 +548,20 @@
   uint32_t m_mtu;
 
   Ptr<Packet> m_currentPkt;
+
+  /**
+   * \brief PPP to Ethernet protocol number mapping
+   * \param protocol A PPP protocol number
+   * \return The corresponding Ethernet protocol number
+   */
+  static uint16_t PppToEther(uint16_t protocol);
+
+  /**
+   * \brief Ethernet to PPP protocol number mapping
+   * \param protocol An Ethernet protocol number
+   * \return The corresponding PPP protocol number
+   */
+  static uint16_t EtherToPpp(uint16_t protocol);
 };
 
 } // namespace ns3
--- a/src/devices/point-to-point/ppp-header.cc	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/devices/point-to-point/ppp-header.cc	Thu Nov 12 09:52:54 2009 +0100
@@ -56,7 +56,7 @@
 void 
 PppHeader::Print (std::ostream &os) const
 {
-  os << "Point-to-Point Protocol: IP (0x0021)";
+  os << "Point-to-Point Protocol: " << m_protocol;
 }
 
   uint32_t
@@ -68,15 +68,27 @@
   void
 PppHeader::Serialize (Buffer::Iterator start) const
 {
-  start.WriteHtonU16 (0x0021);
+  start.WriteHtonU16 (m_protocol);
 }
 
   uint32_t
 PppHeader::Deserialize (Buffer::Iterator start)
 {
-  uint16_t data = start.ReadNtohU16 ();
-  NS_ABORT_MSG_UNLESS (data == 0x0021, "MyHeader::Deserialize(): expected protocol 0x0021");
-  return 2;
+  m_protocol = start.ReadNtohU16 ();
+  return GetSerializedSize();
 }
 
+  void
+PppHeader::SetProtocol (uint16_t protocol)
+{
+  m_protocol=protocol;
+}
+
+  uint16_t
+PppHeader::GetProtocol (void)
+{
+  return m_protocol;
+}
+
+
 } // namespace ns3
--- a/src/devices/point-to-point/ppp-header.h	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/devices/point-to-point/ppp-header.h	Thu Nov 12 09:52:54 2009 +0100
@@ -28,9 +28,9 @@
  *
  * This class can be used to add a header to PPP packet.  Currently we do not
  * implement any of the state machine in RFC 1661, we just encapsulate the
- * inbound packet as an IP version 4 type and send it on.  The goal here is
- * not really to implement the point-to-point protocol, but to encapsulate our
- * packets in a known protocol so packet sniffers can parse them.
+ * inbound packet send it on.  The goal here is not really to implement the
+ * point-to-point protocol, but to encapsulate our packets in a known protocol
+ * so packet sniffers can parse them.
  *
  * if PPP is transmitted over a serial link, it will typically be framed in
  * some way derivative of IBM SDLC (HDLC) with all that that entails.
@@ -41,20 +41,20 @@
  * teach the PcapWriter about the appropriate data link type (DLT_PPP = 9),
  * and we need to add a PPP header to each packet.  Since we are not using
  * framed PPP, this just means prepending the sixteen bit PPP protocol number
- * (0x0021) to the packet.  The ns-3 way to do this is via a class that 
- * inherits from class Header.
+ * to the packet.  The ns-3 way to do this is via a class that inherits from
+ * class Header.
  */
 class PppHeader : public Header 
 {
 public:
 
   /**
-   * \brief Construct an IP version 4 PPP header.
+   * \brief Construct a PPP header.
    */
   PppHeader ();
 
   /**
-   * \brief Destroy an IP version 4 PPP header.
+   * \brief Destroy a PPP header.
    */
   virtual ~PppHeader ();
 
@@ -64,6 +64,31 @@
   virtual void Serialize (Buffer::Iterator start) const;
   virtual uint32_t Deserialize (Buffer::Iterator start);
   virtual uint32_t GetSerializedSize (void) const;
+
+  /**
+   * \brief Set the protocol type carried by this PPP packet
+   *
+   * The type numbers to be used are defined in RFC3818
+   *
+   * \param protocol the protocol type being carried
+   */
+  void SetProtocol(uint16_t protocol);
+
+  /**
+   * \brief Get the protocol type carried by this PPP packet
+   *
+   * The type numbers to be used are defined in RFC3818
+   *
+   * \return the protocol type being carried
+   */
+  uint16_t GetProtocol(void);
+
+private:
+
+  /**
+   * \brief The PPP protocol type of the payload packet
+   */
+  uint16_t m_protocol;
 };
 
 }; // namespace ns3
--- a/src/devices/wifi/yans-wifi-phy.cc	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/devices/wifi/yans-wifi-phy.cc	Thu Nov 12 09:52:54 2009 +0100
@@ -52,14 +52,14 @@
     .AddAttribute ("EnergyDetectionThreshold",
                    "The energy of a received signal should be higher than "
                    "this threshold (dbm) to allow the PHY layer to detect the signal.",
-                   DoubleValue (-140.0),
+                   DoubleValue (-96.0),
                    MakeDoubleAccessor (&YansWifiPhy::SetEdThreshold,
                                        &YansWifiPhy::GetEdThreshold),
                    MakeDoubleChecker<double> ())
     .AddAttribute ("CcaMode1Threshold",
                    "The energy of a received signal should be higher than "
                    "this threshold (dbm) to allow the PHY layer to declare CCA BUSY state",
-                   DoubleValue (-140.0),
+                   DoubleValue (-99.0),
                    MakeDoubleAccessor (&YansWifiPhy::SetCcaMode1Threshold,
                                        &YansWifiPhy::GetCcaMode1Threshold),
                    MakeDoubleChecker<double> ())
--- a/src/internet-stack/ipv4-l3-protocol.cc	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/internet-stack/ipv4-l3-protocol.cc	Thu Nov 12 09:52:54 2009 +0100
@@ -82,8 +82,7 @@
 }
 
 Ipv4L3Protocol::Ipv4L3Protocol()
-  : m_nInterfaces (0),
-    m_identification (0)
+  : m_identification (0)
 {
   NS_LOG_FUNCTION_NOARGS ();
 }
@@ -266,9 +265,8 @@
 Ipv4L3Protocol::AddIpv4Interface (Ptr<Ipv4Interface>interface)
 {
   NS_LOG_FUNCTION (this << interface);
-  uint32_t index = m_nInterfaces;
+  uint32_t index = m_interfaces.size ();
   m_interfaces.push_back (interface);
-  m_nInterfaces++;
   return index;
 }
 
@@ -276,14 +274,9 @@
 Ipv4L3Protocol::GetInterface (uint32_t index) const
 {
   NS_LOG_FUNCTION (this << index);
-  uint32_t tmp = 0;
-  for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); i++)
+  if (index < m_interfaces.size ())
     {
-      if (index == tmp) 
-	{
-	  return *i;
-	}
-      tmp++;
+      return m_interfaces[index];
     }
   return 0;
 }
@@ -292,7 +285,7 @@
 Ipv4L3Protocol::GetNInterfaces (void) const
 {
   NS_LOG_FUNCTION_NOARGS ();
-  return m_nInterfaces;
+  return m_interfaces.size ();
 }
 
 int32_t 
--- a/src/internet-stack/ipv4-l3-protocol.h	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/internet-stack/ipv4-l3-protocol.h	Thu Nov 12 09:52:54 2009 +0100
@@ -22,6 +22,7 @@
 #define IPV4_L3_PROTOCOL_H
 
 #include <list>
+#include <vector>
 #include <stdint.h>
 #include "ns3/ipv4-address.h"
 #include "ns3/ptr.h"
@@ -233,7 +234,7 @@
   Ptr<Icmpv4L4Protocol> GetIcmp (void) const;
   bool IsUnicast (Ipv4Address ad, Ipv4Mask interfaceMask) const;
 
-  typedef std::list<Ptr<Ipv4Interface> > Ipv4InterfaceList;
+  typedef std::vector<Ptr<Ipv4Interface> > Ipv4InterfaceList;
   typedef std::list<Ptr<Ipv4RawSocketImpl> > SocketList;
   typedef std::list<Ptr<Ipv4L4Protocol> > L4List_t;
 
--- a/src/mobility/mobility.h	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/mobility/mobility.h	Thu Nov 12 09:52:54 2009 +0100
@@ -28,4 +28,9 @@
  *   - ns3::RandomDirection2dMobilityModel: a 2d random direction mobility
  *     model where the bounds of the mobility are are a rectangle.
  *
+ *   - ns3::WaypointMobilityModel: A model which determines paths from sets
+ *     of ns3::Waypoint objects, similar to using events to update velocity
+ *     and direction with a ns3::ConstantVelocityMobilityModel. This model
+ *     is slightly faster for this task and uses less memory.
+ *
  */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mobility/waypoint-mobility-model.cc	Thu Nov 12 09:52:54 2009 +0100
@@ -0,0 +1,180 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009 Phillip Sitbon
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Phillip Sitbon <phillip@sitbon.net>
+ */
+#include <limits>
+#include "ns3/abort.h"
+#include "ns3/simulator.h"
+#include "ns3/uinteger.h"
+#include "ns3/log.h"
+#include "waypoint-mobility-model.h"
+
+NS_LOG_COMPONENT_DEFINE ("WaypointMobilityModel");
+
+namespace ns3 {
+
+NS_OBJECT_ENSURE_REGISTERED (WaypointMobilityModel);
+
+
+TypeId
+WaypointMobilityModel::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::WaypointMobilityModel")
+    .SetParent<MobilityModel> ()
+    .SetGroupName ("Mobility")
+    .AddConstructor<WaypointMobilityModel> ()
+    .AddAttribute ("NextWaypoint", "The next waypoint used to determine position.",
+                   TypeId::ATTR_GET,
+                   WaypointValue (),
+                   MakeWaypointAccessor (&WaypointMobilityModel::GetNextWaypoint),
+                   MakeWaypointChecker ())
+    .AddAttribute ("WaypointsLeft", "The number of waypoints remaining.",
+                   TypeId::ATTR_GET,
+                   UintegerValue (0),
+                   MakeUintegerAccessor (&WaypointMobilityModel::WaypointsLeft),
+                   MakeUintegerChecker<uint32_t> ())
+    ;
+  return tid;
+}
+
+
+WaypointMobilityModel::WaypointMobilityModel ()
+ : m_first (true)
+{
+}
+WaypointMobilityModel::~WaypointMobilityModel ()
+{
+}
+void 
+WaypointMobilityModel::DoDispose (void)
+{
+  MobilityModel::DoDispose ();
+}
+void
+WaypointMobilityModel::AddWaypoint (const Waypoint &waypoint)
+{
+  if ( m_first )
+    {
+      m_first = false;
+      m_current = m_next = waypoint;
+    }
+  else
+    {
+      NS_ABORT_MSG_IF ( !m_waypoints.empty () && (m_waypoints.back ().time >= waypoint.time),
+                        "Waypoints must be added in ascending time order");
+      m_waypoints.push_back (waypoint);
+    }
+}
+Waypoint
+WaypointMobilityModel::GetNextWaypoint (void) const
+{
+  Update ();
+  return m_next;
+}
+uint32_t
+WaypointMobilityModel::WaypointsLeft (void) const
+{
+  Update ();
+  return m_waypoints.size();
+}
+void
+WaypointMobilityModel::Update (void) const
+{
+  const Time now = Simulator::Now ();
+  bool newWaypoint = false;
+
+  if ( now <= m_current.time )
+    {
+      return;
+    }
+
+  while ( now >= m_next.time  )
+    {
+      if ( m_waypoints.empty () )
+        {
+          if ( m_current.time <= m_next.time )
+            {
+              m_current.position = m_next.position;
+              m_current.time = now;
+              m_velocity = Vector (0,0,0);
+              NotifyCourseChange ();
+            }
+          else
+            {
+              m_current.time = now;
+            }
+
+          return;
+        }
+
+      m_current = m_next;
+      m_next = m_waypoints.front ();
+      m_waypoints.pop_front ();
+      newWaypoint = true;
+
+      const double t_span = (m_next.time - m_current.time).GetSeconds ();
+      NS_ASSERT (t_span > 0);
+      m_velocity.x = (m_next.position.x - m_current.position.x) / t_span;
+      m_velocity.y = (m_next.position.y - m_current.position.y) / t_span;
+      m_velocity.z = (m_next.position.z - m_current.position.z) / t_span;
+    }
+
+
+  const double t_diff = (now - m_current.time).GetSeconds();
+  m_current.position.x += m_velocity.x * t_diff;
+  m_current.position.y += m_velocity.y * t_diff;
+  m_current.position.z += m_velocity.z * t_diff;
+  m_current.time = now;
+
+  if ( newWaypoint )
+    {
+      NotifyCourseChange ();
+    }
+}
+Vector
+WaypointMobilityModel::DoGetPosition (void) const
+{
+  Update ();
+  return m_current.position;
+}
+void
+WaypointMobilityModel::DoSetPosition (const Vector &position)
+{
+  const Time now = Simulator::Now ();
+  Update ();
+  m_current.time = std::max (now, m_next.time);
+  m_current.position = position;
+  m_velocity = Vector (0,0,0);
+  NotifyCourseChange ();
+}
+void
+WaypointMobilityModel::EndMobility (void)
+{
+  m_waypoints.clear ();
+  m_current.time = Seconds (std::numeric_limits<double>::infinity ());
+  m_next.time = m_current.time;
+  m_first = true;
+}
+Vector
+WaypointMobilityModel::DoGetVelocity (void) const
+{
+  return m_velocity;
+}
+
+} // namespace ns3
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mobility/waypoint-mobility-model.h	Thu Nov 12 09:52:54 2009 +0100
@@ -0,0 +1,115 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009 Phillip Sitbon
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Phillip Sitbon <phillip@sitbon.net>
+ */
+#ifndef WAYPOINT_MOBILITY_MODEL_H
+#define WAYPOINT_MOBILITY_MODEL_H
+
+#include <stdint.h>
+#include <deque>
+#include "mobility-model.h"
+#include "ns3/vector.h"
+#include "waypoint.h"
+
+namespace ns3 {
+
+/**
+ * \brief a waypoint-based mobility model
+ *
+ * Each object determines its velocity and position at a given time
+ * from a set of ns3::Waypoint objects. The position of each object
+ * is not updated unless queried, and past waypoints are discarded
+ * after the current simulation time greater than their time value.
+ * 
+ * The initial position of each object corresponds to the position of
+ * the first waypoint, and the initial velocity of each object is zero.
+ * Upon reaching the last waypoint, object positions becomes static and
+ * velocity is zero.
+ *
+ * When a node is in between waypoints (in time), it moves with a constant
+ * velocity between the position at the previous waypoint and the position
+ * at the current waypoint. To make a node hold a certain position for a
+ * time interval, two waypoints with the same position (but different times)
+ * should be inserted sequentially.
+ *
+ * Waypoints can be added at any time, and setting the current position
+ * of an object will set its velocity to zero until the next waypoint time
+ * (at which time the object jumps to the next waypoint), unless there are
+ * no more waypoints in which case it will not change without user
+ * intervention.
+ *
+ */
+class WaypointMobilityModel : public MobilityModel
+{
+ public:
+  static TypeId GetTypeId (void);
+
+  /**
+   * Create a path with no waypoints at location (0,0,0).
+   */
+  WaypointMobilityModel ();
+  virtual ~WaypointMobilityModel ();
+
+  /**
+   * \param waypoint waypoint to append to the object path.
+   *
+   * Add a waypoint to the path of the object. The time must
+   * be greater than the previous waypoint added, otherwise
+   * a fatal error occurs. The first waypoint is set as the
+   * current position with a velocity of zero.
+   * 
+   */
+  void AddWaypoint (const Waypoint &waypoint);
+
+  /**
+   * Get the waypoint that this object is traveling towards.
+   */
+  Waypoint GetNextWaypoint (void) const;
+
+  /**
+   * Get the number of waypoints left for this object, excluding
+   * the next one.
+   */
+  uint32_t WaypointsLeft (void) const;
+
+  /**
+   * Clear any existing waypoints and set the current waypoint
+   * time to infinity. Calling this is only an optimization and
+   * not required. After calling this function, adding waypoints
+   * behaves as it would for a new object.
+   */
+  void EndMobility (void);
+
+ private:
+  void Update (void) const;
+  virtual void DoDispose (void);
+  virtual Vector DoGetPosition (void) const;
+  virtual void DoSetPosition (const Vector &position);
+  virtual Vector DoGetVelocity (void) const;
+
+  bool m_first;
+  mutable std::deque<Waypoint> m_waypoints;
+  mutable Waypoint m_current;
+  mutable Waypoint m_next;
+  mutable Vector m_velocity;
+};
+
+} // namespace ns3
+
+#endif /* WAYPOINT_MOBILITY_MODEL_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mobility/waypoint.cc	Thu Nov 12 09:52:54 2009 +0100
@@ -0,0 +1,52 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009 Phillip Sitbon
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Phillip Sitbon <phillip@sitbon.net>
+ */
+#include "waypoint.h"
+
+namespace ns3 {
+
+ATTRIBUTE_HELPER_CPP (Waypoint);
+
+Waypoint::Waypoint (const Time &waypointTime, const Vector &waypointPosition)
+  : time (waypointTime),
+  position (waypointPosition)
+{}
+Waypoint::Waypoint ()
+  : time (0.0),
+  position (0,0,0)
+{}
+
+std::ostream &operator << (std::ostream &os, const Waypoint &waypoint)
+{
+  os << waypoint.time.GetSeconds () << "$" << waypoint.position;
+  return os;
+}
+std::istream &operator >> (std::istream &is, Waypoint &waypoint)
+{
+  char separator;
+  is >> waypoint.time >> separator >> waypoint.position;
+  if (separator != '$')
+    {
+      is.setstate (std::ios_base::failbit);
+    }
+  return is;
+}
+
+} // namespace ns3
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mobility/waypoint.h	Thu Nov 12 09:52:54 2009 +0100
@@ -0,0 +1,69 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009 Phillip Sitbon
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Phillip Sitbon <phillip@sitbon.net>
+ */
+#ifndef WAYPOINT_H
+#define WAYPOINT_H
+
+#include "ns3/attribute.h"
+#include "ns3/attribute-helper.h"
+#include "ns3/nstime.h"
+#include "ns3/vector.h"
+
+namespace ns3 {
+
+/**
+ * \brief a (time, location) pair.
+ *
+ */
+class Waypoint
+{
+public:
+  /**
+   * \param _time time of waypoint.
+   * \param _position position of waypoint corresponding to the given time.
+   *
+   * Create a waypoint.
+   */
+  Waypoint (const Time &waypointTime, const Vector &waypointPosition);
+
+  /**
+   * Create a waypoint at time 0 and position (0,0,0).
+   */
+  Waypoint ();
+  /* The waypoint time */
+  Time time;
+  /* The position of the waypoint */
+  Vector position;
+};
+
+/**
+ * \class ns3::WaypointValue
+ * \brief hold objects of type ns3::Waypoint
+ */
+ATTRIBUTE_HELPER_HEADER ( Waypoint);
+
+std::ostream &
+operator << (std::ostream &os, const Waypoint &waypoint);
+std::istream &
+operator >> (std::istream &is, Waypoint &waypoint);
+
+} // namespace ns3
+
+#endif /* WAYPOINT_H */
+
--- a/src/mobility/wscript	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/mobility/wscript	Thu Nov 12 09:52:54 2009 +0100
@@ -14,6 +14,8 @@
         'random-walk-2d-mobility-model.cc',
         'random-direction-2d-mobility-model.cc',
         'constant-acceleration-mobility-model.cc',
+        'waypoint.cc',
+        'waypoint-mobility-model.cc',
         ]
 
     headers = bld.new_task_gen('ns3header')
@@ -30,4 +32,6 @@
         'random-walk-2d-mobility-model.h',
         'random-direction-2d-mobility-model.h',
         'constant-acceleration-mobility-model.h',
+        'waypoint.h',
+        'waypoint-mobility-model.h',
         ]
--- a/src/simulator/simulator.cc	Wed Nov 11 16:25:10 2009 +0100
+++ b/src/simulator/simulator.cc	Thu Nov 12 09:52:54 2009 +0100
@@ -297,6 +297,12 @@
       NS_FATAL_ERROR ("It is not possible to set the implementation after calling any Simulator:: function. Call Simulator::SetImplementation earlier or after Simulator::Destroy.");
     }
   *PeekImpl () = impl;
+  // Set the default scheduler
+  ObjectFactory factory;
+  StringValue s;
+  g_schedTypeImpl.GetValue (s);
+  factory.SetTypeId (s.Get ());
+  impl->SetScheduler (factory.Create<Scheduler> ());
 //
 // Note: we call LogSetTimePrinter _after_ creating the implementation
 // object because the act of creation can trigger calls to the logging 
--- a/test.py	Wed Nov 11 16:25:10 2009 +0100
+++ b/test.py	Thu Nov 12 09:52:54 2009 +0100
@@ -132,6 +132,7 @@
     ("tutorial/second", "True", "True"),
     ("tutorial/third", "True", "True"),
     ("tutorial/fourth", "True", "True"),
+    ("tutorial/fifth", "True", "True"),
 
     ("udp/udp-echo", "True", "True"),
 
@@ -616,6 +617,7 @@
         self.shell_command = ""
         self.display_name = ""
         self.basedir = ""
+        self.tempdir = ""
         self.cwd = ""
         self.tmp_file_name = ""
         self.returncode = False
@@ -674,6 +676,13 @@
         self.basedir = basedir
 
     #
+    # This is the directory to which a running test suite should write any 
+    # temporary files.
+    #
+    def set_tempdir(self, tempdir):
+        self.tempdir = tempdir
+
+    #
     # This is the current working directory that will be given to an executing
     # test as it is being run.  It will be used for examples to tell them where
     # to write all of the pcap files that we will be carefully ignoring.  For
@@ -766,7 +775,8 @@
                     # file name
                     #
                     (job.returncode, standard_out, standard_err, et) = run_job_synchronously(job.shell_command + 
-                        " --basedir=%s --out=%s" % (job.basedir, job.tmp_file_name), job.cwd, options.valgrind)
+                        " --basedir=%s --tempdir=%s --out=%s" % (job.basedir, job.tempdir, job.tmp_file_name), 
+                        job.cwd, options.valgrind)
 
                 job.set_elapsed_time(et)
 
@@ -1004,6 +1014,7 @@
             job.set_tmp_file_name(os.path.join(testpy_output_dir, "%s.xml" % test))
             job.set_cwd(os.getcwd())
             job.set_basedir(os.getcwd())
+            job.set_tempdir(testpy_output_dir)
             if (options.multiple):
                 multiple = " --multiple"
             else:
@@ -1074,6 +1085,7 @@
                         job.set_tmp_file_name("")
                         job.set_cwd(testpy_output_dir)
                         job.set_basedir(os.getcwd())
+                        job.set_tempdir(testpy_output_dir)
                         job.set_shell_command("examples/%s" % test)
 
                         if options.valgrind and not eval(do_valgrind_run):
@@ -1097,6 +1109,7 @@
         job.set_tmp_file_name("")
         job.set_cwd(testpy_output_dir)
         job.set_basedir(os.getcwd())
+        job.set_tempdir(testpy_output_dir)
         job.set_shell_command("examples/%s" % options.example)
         
         if options.verbose:
--- a/utils/test-runner.cc	Wed Nov 11 16:25:10 2009 +0100
+++ b/utils/test-runner.cc	Thu Nov 12 09:52:54 2009 +0100
@@ -40,11 +40,13 @@
   bool doKinds = false;
 
   bool haveBasedir = false;
+  bool haveTempdir = false;
   bool haveOutfile = false;
   bool haveType = false;
 
   std::string suiteName;
   std::string basedir;
+  std::string tempdir;
   std::string outfileName;
   std::string typeName;
 
@@ -96,6 +98,12 @@
           doSuite = true;
         }
 
+      if (arg.find ("--tempdir=") != std::string::npos)
+        {
+          tempdir = arg.substr (arg.find_first_of ("=") + 1, 9999);
+          haveTempdir = true;
+        }
+
       if (arg.compare ("--verbose") == 0)
         {
           doVerbose = true;
@@ -247,6 +255,7 @@
       if (doSuite == false || (doSuite == true && suiteName == testSuite->GetName ()))
         {
           testSuite->SetBaseDir (basedir);
+          testSuite->SetTempDir (tempdir);
           testSuite->SetStream (pofs);
           testSuite->SetVerbose (doVerbose);
           testSuite->SetContinueOnFailure (doMultiple);