Simplifications to the point to point devices and channel
authorGeorge F. Riley<riley@ece.gatech.edu>
Fri, 13 Jul 2007 10:40:10 +0200
changeset 926 1fdec986d774
parent 925 914adb9a1aab
child 927 b5bc396a29b0
Simplifications to the point to point devices and channel
src/devices/p2p/p2p-channel.cc
src/devices/p2p/p2p-channel.h
src/devices/p2p/p2p-net-device.cc
src/devices/p2p/p2p-net-device.h
src/node/mac-address.cc
src/node/mac-address.h
src/simulator/simulator.h
--- a/src/devices/p2p/p2p-channel.cc	Tue Jul 10 13:45:20 2007 +0100
+++ b/src/devices/p2p/p2p-channel.cc	Fri Jul 13 10:40:10 2007 +0200
@@ -76,8 +76,7 @@
   NS_ASSERT(m_nDevices < N_DEVICES && "Only two devices permitted");
   NS_ASSERT(device != 0);
 
-  m_link[m_nDevices].m_src = device;
-  ++m_nDevices;
+  m_link[m_nDevices++].m_src = device;
 //
 // If we have both devices connected to the channel, then finish introducing
 // the two halves and set the links to IDLE.
@@ -91,8 +90,9 @@
     }
 }
 
-bool
-PointToPointChannel::TransmitStart(Packet& p, Ptr<PointToPointNetDevice> src)
+bool PointToPointChannel::TransmitStart(Packet& p,
+                                        Ptr<PointToPointNetDevice> src,
+                                        const Time& txTime)
 {
   NS_DEBUG ("PointToPointChannel::TransmitStart (" << &p << ", " << src << 
             ")");
@@ -104,65 +104,15 @@
 
   uint32_t wire = src == m_link[0].m_src ? 0 : 1;
 
-  if (m_link[wire].m_state == TRANSMITTING)
-    {
-      NS_DEBUG("PointToPointChannel::TransmitStart (): **** ERROR ****");
-      NS_DEBUG("PointToPointChannel::TransmitStart (): state TRANSMITTING");
-      return false;
-    }
-
-  NS_DEBUG("PointToPointChannel::TransmitStart (): switch to TRANSMITTING");
-  m_link[wire].m_state = TRANSMITTING;
+  // Here we schedule the packet receive event at the receiver,
+  // which simplifies this model quite a bit.  The channel just
+  // adds the propagation delay time
+  Simulator::Schedule (txTime + m_delay,
+                       &PointToPointNetDevice::Receive,
+                       m_link[wire].m_dst, p);
   return true;
 }
 
-bool
-PointToPointChannel::TransmitEnd(Packet& p, Ptr<PointToPointNetDevice> src)
-{
-  NS_DEBUG("PointToPointChannel::TransmitEnd (" << &p << ", " << src << ")");
-  NS_DEBUG ("PointToPointChannel::TransmitEnd (): UID is " << 
-            p.GetUid () << ")");
-
-  NS_ASSERT(m_link[0].m_state != INITIALIZING);
-  NS_ASSERT(m_link[1].m_state != INITIALIZING);
-
-  uint32_t wire = src == m_link[0].m_src ? 0 : 1;
-
-  NS_ASSERT(m_link[wire].m_state == TRANSMITTING);
-
-  m_link[wire].m_state = PROPAGATING;
-//
-// The sender is going to free the packet as soon as it has been transmitted.
-// We need to copy it to get a reference so it won't e deleted.
-//
-  Packet packet = p;
-  NS_DEBUG ("PointToPointChannel::TransmitEnd (): Schedule event in " << 
-            m_delay.GetSeconds () << "sec");
-  Simulator::Schedule (m_delay,
-                       &PointToPointChannel::PropagationCompleteEvent,
-                       this, packet, src);
-  return true;
-}
-
-void
-PointToPointChannel::PropagationCompleteEvent(
-  Packet p, 
-  Ptr<PointToPointNetDevice> src)
-{
-  NS_DEBUG("PointToPointChannel::PropagationCompleteEvent (" << &p << ", " << 
-    src << ")");
-  NS_DEBUG ("PointToPointChannel::PropagationCompleteEvent (): UID is " << 
-    p.GetUid () << ")");
-
-  uint32_t wire = src == m_link[0].m_src ? 0 : 1;
-  NS_ASSERT(m_link[wire].m_state == PROPAGATING);
-  m_link[wire].m_state = IDLE;
-
-  NS_DEBUG ("PointToPointChannel::PropagationCompleteEvent (): Receive");
-  m_link[wire].m_dst->Receive (p);
-}
-
-
 uint32_t 
 PointToPointChannel::GetNDevices (void) const
 {
@@ -176,13 +126,13 @@
   return m_link[i].m_src;
 }
 
-  DataRate
+const DataRate&
 PointToPointChannel::GetDataRate (void)
 {
   return m_bps;
 }
 
-  Time
+const Time&
 PointToPointChannel::GetDelay (void)
 {
   return m_delay;
--- a/src/devices/p2p/p2p-channel.h	Tue Jul 10 13:45:20 2007 +0100
+++ b/src/devices/p2p/p2p-channel.h	Fri Jul 13 10:40:10 2007 +0200
@@ -51,11 +51,7 @@
  */
 class PointToPointChannel : public Channel {
 public:
-//
-// This is really kidding myself, since just setting N_DEVICES to 3 isn't
-// going to come close to magically creating a multi-drop link, but I can't
-// bring myself to just type 2 in the code (even though I type 0 and 1 :-).
-//
+// Each point to point link has exactly two net devices
   static const int N_DEVICES = 2;
   /**
    * \brief Create a PointToPointChannel
@@ -68,7 +64,7 @@
   /**
    * \brief Create a PointToPointChannel
    *
-   * \param bps The bitrate of the channel
+   * \param bps The maximum bitrate of the channel
    * \param delay Transmission delay through the channel
    */  
   PointToPointChannel (const DataRate& bps, const Time& delay);
@@ -77,7 +73,7 @@
    * \brief Create a PointToPointChannel
    *
    * \param name the name of the channel for identification purposes
-   * \param bps The bitrate of the channel
+   * \param bps The maximum bitrate of the channel
    * \param delay Transmission delay through the channel
    */
   PointToPointChannel (const std::string& name,
@@ -88,21 +84,22 @@
    * \param device pointer to the netdevice to attach to the channel
    */
   void Attach (Ptr<PointToPointNetDevice> device);
-  bool TransmitStart (Packet& p, Ptr<PointToPointNetDevice> src);
-  bool TransmitEnd (Packet &p, Ptr<PointToPointNetDevice> src);
-  void PropagationCompleteEvent(Packet p, Ptr<PointToPointNetDevice> src);
+  bool TransmitStart (Packet& p, Ptr<PointToPointNetDevice> src,
+                      const Time& txTime);
+  // Below two not needed
+  //bool TransmitEnd (Packet &p, Ptr<PointToPointNetDevice> src);
+  //void PropagationCompleteEvent(Packet p, Ptr<PointToPointNetDevice> src);
 
 
   virtual uint32_t GetNDevices (void) const;
   virtual Ptr<NetDevice> GetDevice (uint32_t i) const;
 
-  virtual DataRate GetDataRate (void);
-  virtual Time GetDelay (void);
+  virtual const DataRate& GetDataRate (void);
+  virtual const Time&     GetDelay (void);
 
 private:
   DataRate      m_bps;
   Time          m_delay;
-
   int32_t       m_nDevices;
 
   enum WireState
--- a/src/devices/p2p/p2p-net-device.cc	Tue Jul 10 13:45:20 2007 +0100
+++ b/src/devices/p2p/p2p-net-device.cc	Fri Jul 13 10:40:10 2007 +0200
@@ -16,7 +16,8 @@
  * 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@sophia.inria.fr>
+ * Author:  Craig Dowell <craigdo@ee.washington.edu>
+ * Revised: George Riley <riley@ece.gatech.edu>
  */
 
 #include <iostream>
@@ -32,11 +33,17 @@
 
 namespace ns3 {
 
-PointToPointNetDevice::PointToPointNetDevice (Ptr<Node> node) 
+DataRateDefaultValue PointToPointNetDevice::g_defaultRate(
+           "PointToPointLinkDataRate", 
+           "The default data rate for point to point links",
+           DataRate ("10Mb/s"));
+
+  PointToPointNetDevice::PointToPointNetDevice (Ptr<Node> node,
+                                                const DataRate& rate) 
 : 
-  NetDevice(node, MacAddress ("00:00:00:00:00:00")), 
+  NetDevice(node, MacAddress (6)), 
   m_txMachineState (READY),
-  m_bps (DataRate (0xffffffff)),
+  m_bps (rate),
   m_tInterframeGap (Seconds(0)),
   m_channel (0), 
   m_queue (0),
@@ -73,6 +80,9 @@
 // We're assuming that the tracing will be set up after the topology creation
 // phase and this won't actually matter.
 //
+// GFR Comments.  Don't see where the "copy the pointer and add reference"
+// stated above is done. Can original author please comment and/or fix.
+// Shouldn't the queue pointer also bump the refcount?
 PointToPointNetDevice::PointToPointNetDevice (const PointToPointNetDevice& nd)
 : 
   NetDevice(nd), 
@@ -92,6 +102,8 @@
     
 }
 
+  // GFR COmments...shouldn't this decrement the refcount instead
+  // of just nil-ing out the pointer?  Don't understand this.
 void PointToPointNetDevice::DoDispose()
 {
   m_channel = 0;
@@ -101,100 +113,54 @@
 //
 // Assignment operator for PointToPointNetDevice.
 //
-// This uses the non-obvious trick of taking the source net device passed by
-// value instead of by reference.  This causes the copy constructor to be
-// invoked (where the real work is done -- see above).  All we have to do
-// here is to return the newly constructed net device.
 //
-  PointToPointNetDevice&
-PointToPointNetDevice::operator= (const PointToPointNetDevice nd)
+PointToPointNetDevice&
+PointToPointNetDevice::operator= (const PointToPointNetDevice& nd)
 {
   NS_DEBUG ("PointToPointNetDevice::operator= (" << &nd << ")");
+  // FIXME.  Not sure what to do here
+  // GFR Note.  I would suggest dis-allowing netdevice assignment,
+  // as well as pass-by-value (ie. copy constructor).
+  // This resolves some of the questions above about copy constructors.
+  // Why should we ever copy or assign a net device?
   return *this;
 }
 
-  void 
-PointToPointNetDevice::SetDataRate(DataRate bps)
+void PointToPointNetDevice::SetDataRate(const DataRate& bps)
 {
   m_bps = bps;
 }
 
-  void 
-PointToPointNetDevice::SetInterframeGap(Time t)
+void PointToPointNetDevice::SetInterframeGap(const Time& t)
 {
   m_tInterframeGap = t;
 }
 
-  bool
-PointToPointNetDevice::SendTo (Packet& p, const MacAddress& dest)
+bool PointToPointNetDevice::SendTo (Packet& p, const MacAddress& dest)
 {
   NS_DEBUG ("PointToPointNetDevice::SendTo (" << &p << ", " << &dest << ")");
   NS_DEBUG ("PointToPointNetDevice::SendTo (): UID is " << p.GetUid () << ")");
 
+  // GFR Comment. Why is this an assertion? Can't a link legitimately
+  // "go down" during the simulation?  Shouldn't we just wait for it
+  // to come back up?
   NS_ASSERT (IsLinkUp ());
 
-#ifdef NOTYET
-    struct NetDevicePacketDestAddress tag;
-    tag.address = address;
-    p.AddTag (tag);
-#endif
-
 //
 // This class simulates a point to point device.  In the case of a serial
-// link, this means that we're simulating something like a UART.  This is
-// not a requirement for a point-to-point link, but it's a typical model for
-// the device.  
-//
-// Generally, a real device will have a list of pending packets to transmit.  
-// An on-device CPU frees the main CPU(s) of the details of what is happening
-// in the device and feeds the USART.  The main CPU basically just sees the 
-// list of packets -- it puts packets into the list, and the device frees the
-// packets when they are transmitted.
+// link, this means that we're simulating something like a UART.
 //
-// In the case of our virtual device here, the queue pointed to by m_queue
-// corresponds to this list.  The main CPU adds packets to the list by 
-// calling this method and when the device completes a send, the packets are
-// freed in an "interrupt" service routine.
-//
-// We're going to do the same thing here.  So first of all, the incoming packet
-// goes onto our queue if possible.  If the queue can't handle it, there's
-// nothing to be done.
-//
-    if (m_queue->Enqueue(p) == false )
-      {
-        return false;
-      }
 //
-// If there's a transmission in progress, the "interrupt" will keep the
-// transmission process going.  If the device is idle, we need to start a
-// transmission.
-//
-// In the real world, the USART runs until it finishes sending bits, and then
-// pulls on the device's transmit complete interrupt wire.  At the same time,
-// the electrons from the last wiggle of the wire are busy propagating down
-// the wire.  In the case of a long speed-of-light delay in the wire, we could
-// conceivably start transmitting the next packet before the end of the 
-// previously sent data has even reached the end of the wire.  This situation
-// is usually avoided (like the plague) and an "interframe gap" is introduced.
-// This is usually the round-trip delay on the channel plus some hard-to-
-// quantify receiver turn-around time (the time required for the receiver
-// to process the last frame and prepare for reception of the next).
-//
-// So, if the transmit machine is ready, we need to schedule a transmit 
-// complete event (at which time we tell the channel we're no longer sending
-// bits).  A separate transmit ready event (at which time the transmitter 
-// becomes ready to start sending bits again is scheduled there).  Finally, 
-// we tell the channel (via TransmitStart ()) that we've started wiggling the 
-// wire and bits are coming out.
-//
-// If the transmit machine is not ready, we just leave and the transmit ready
-// event we know is coming will kick-start the transmit process.
-//
+// If there's a transmission in progress, we enque the packet for later
+// trnsmission; otherwise we send it now.
     if (m_txMachineState == READY) 
       {
         return TransmitStart (p);
       }
-    return true;
+    else
+      {
+        return m_queue->Enqueue(p);
+      }
 }
 
   bool
@@ -206,81 +172,41 @@
 //
 // This function is called to start the process of transmitting a packet.
 // We need to tell the channel that we've started wiggling the wire and
-// schedule an event that will be executed when it's time to tell the 
-// channel that we're done wiggling the wire.
+// schedule an event that will be executed when the transmission is complete.
 //
   NS_ASSERT_MSG(m_txMachineState == READY, "Must be READY to transmit");
   m_txMachineState = BUSY;
-  Time tEvent = Seconds (m_bps.CalculateTxTime(p.GetSize()));
+  Time txTime = Seconds (m_bps.CalculateTxTime(p.GetSize()));
+  Time txCompleteTime = txTime + m_tInterframeGap;
 
   NS_DEBUG ("PointToPointNetDevice::TransmitStart (): " <<
     "Schedule TransmitCompleteEvent in " << 
-    tEvent.GetSeconds () << "sec");
-
-  Simulator::Schedule (tEvent, 
-                       &PointToPointNetDevice::TransmitCompleteEvent, 
+    txCompleteTime.GetSeconds () << "sec");
+  // Schedule the tx complete event
+  Simulator::Schedule (txCompleteTime, 
+                       &PointToPointNetDevice::TransmitComplete, 
                        this);
-  return m_channel->TransmitStart (p, this); 
+  return m_channel->TransmitStart(p, this, txTime); 
 }
 
-  void
-PointToPointNetDevice::TransmitCompleteEvent (void)
+void PointToPointNetDevice::TransmitComplete (void)
 {
   NS_DEBUG ("PointToPointNetDevice::TransmitCompleteEvent ()");
 //
 // This function is called to finish the  process of transmitting a packet.
 // We need to tell the channel that we've stopped wiggling the wire and
-// schedule an event that will be executed when it's time to re-enable
-// the transmitter after the interframe gap.
+// get the next packet from the queue.  If the queue is empty, we are
+// done, otherwise transmit the next packet.
 //
   NS_ASSERT_MSG(m_txMachineState == BUSY, "Must be BUSY if transmitting");
-  m_txMachineState = GAP;
+  m_txMachineState = READY;
   Packet p;
-  bool found;
-  found = m_queue->Dequeue (p);
-  NS_ASSERT_MSG(found, "Packet must be on queue if transmitted");
-  NS_DEBUG ("PointToPointNetDevice::TransmitCompleteEvent (): Pkt UID is " << 
-            p.GetUid () << ")");
-  m_channel->TransmitEnd (p, this); 
-
-  NS_DEBUG (
-    "PointToPointNetDevice::TransmitCompleteEvent (): " <<
-    "Schedule TransmitReadyEvent in "
-    << m_tInterframeGap.GetSeconds () << "sec");
-
-  Simulator::Schedule (m_tInterframeGap, 
-                       &PointToPointNetDevice::TransmitReadyEvent, 
-                       this);
+  if (!m_queue->Dequeue(p)) return; // Nothing to do at this point
+  TransmitStart(p);
 }
 
-  void
-PointToPointNetDevice::TransmitReadyEvent (void)
-{
-  NS_DEBUG ("PointToPointNetDevice::TransmitReadyEvent ()");
-//
-// This function is called to enable the transmitter after the interframe
-// gap has passed.  If there are pending transmissions, we use this opportunity
-// to start the next transmit.
-//
-  NS_ASSERT_MSG(m_txMachineState == GAP, "Must be in interframe gap");
-  m_txMachineState = READY;
-
-  if (m_queue->IsEmpty())
-    {
-      return;
-    }
-  else
-    {
-      Packet p;
-      bool found;
-      found = m_queue->Peek (p);
-      NS_ASSERT_MSG(found, "IsEmpty false but no Packet on queue?");
-      TransmitStart (p);
-    }
-}
-
-TraceResolver *
-PointToPointNetDevice::DoCreateTraceResolver (TraceContext const &context)
+TraceResolver* PointToPointNetDevice::DoCreateTraceResolver (
+                                      TraceContext const &context)
 {
   CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
   resolver->Add ("queue", 
@@ -292,8 +218,7 @@
   return resolver;
 }
 
-bool
-PointToPointNetDevice::Attach (Ptr<PointToPointChannel> ch)
+bool PointToPointNetDevice::Attach (Ptr<PointToPointChannel> ch)
 {
   NS_DEBUG ("PointToPointNetDevice::Attach (" << &ch << ")");
 
@@ -301,7 +226,9 @@
 
   m_channel->Attach(this);
   m_bps = m_channel->GetDataRate ();
-  m_tInterframeGap = m_channel->GetDelay ();
+  // GFR Comment.  Below is definitely wrong.  Interframe gap
+  // is unrelated to channel delay.
+  //m_tInterframeGap = m_channel->GetDelay ();
 
   /* 
    * For now, this device is up whenever a channel is attached to it.
@@ -315,38 +242,32 @@
   return true;
 }
 
-void
-PointToPointNetDevice::AddQueue (Ptr<Queue> q)
+void PointToPointNetDevice::AddQueue (Ptr<Queue> q)
 {
   NS_DEBUG ("PointToPointNetDevice::AddQueue (" << q << ")");
 
   m_queue = q;
 }
 
-void
-PointToPointNetDevice::Receive (Packet& p)
+void PointToPointNetDevice::Receive (Packet& p)
 {
-  // ignore return value for now.
   NS_DEBUG ("PointToPointNetDevice::Receive (" << &p << ")");
 
   m_rxTrace (p);
   ForwardUp (p);
 }
 
-Ptr<Queue>
-PointToPointNetDevice::GetQueue(void) const 
+Ptr<Queue> PointToPointNetDevice::GetQueue(void) const 
 { 
     return m_queue;
 }
 
-Ptr<Channel>
-PointToPointNetDevice::DoGetChannel(void) const 
+Ptr<Channel> PointToPointNetDevice::DoGetChannel(void) const 
 { 
     return m_channel;
 }
 
-bool 
-PointToPointNetDevice::DoNeedsArp (void) const
+bool PointToPointNetDevice::DoNeedsArp (void) const
 {
   return false;
 }
--- a/src/devices/p2p/p2p-net-device.h	Tue Jul 10 13:45:20 2007 +0100
+++ b/src/devices/p2p/p2p-net-device.h	Fri Jul 13 10:40:10 2007 +0200
@@ -30,6 +30,7 @@
 #include "ns3/callback-trace-source.h"
 #include "ns3/nstime.h"
 #include "ns3/data-rate.h"
+#include "ns3/default-value.h"
 #include "ns3/ptr.h"
 
 namespace ns3 {
@@ -80,7 +81,8 @@
    * @see PointToPointTopology::AddPointToPointLink ()
    * @param node the Node to which this device is connected.
    */
-  PointToPointNetDevice (Ptr<Node> node);
+  PointToPointNetDevice (Ptr<Node> node,
+                         const DataRate& = g_defaultRate.GetValue());
   /**
    * Copy Construct a PointToPointNetDevice
    *
@@ -105,7 +107,7 @@
    *
    * @param nd the object to be copied
    */
-  PointToPointNetDevice& operator= (PointToPointNetDevice nd);
+  PointToPointNetDevice& operator= (const PointToPointNetDevice& nd);
   /**
    * Set the Data Rate used for transmission of packets.  The data rate is
    * set in the Attach () method from the corresponding field in the channel
@@ -114,7 +116,7 @@
    * @see Attach ()
    * @param bps the data rate at which this object operates
    */
-  void SetDataRate(DataRate bps);
+  void SetDataRate(const DataRate& bps);
   /**
    * Set the inteframe gap used to separate packets.  The interframe gap
    * defines the minimum space required between packets sent by this device.
@@ -125,7 +127,7 @@
    * @see Attach ()
    * @param t the interframe gap time
    */
-  void SetInterframeGap(Time t);
+  void SetInterframeGap(const Time& t);
   /**
    * Attach the device to a channel.
    *
@@ -190,6 +192,19 @@
    * @returns a pointer to the channel
    */
   virtual Ptr<Channel> DoGetChannel(void) const;
+  /**
+   * Set a new default data rate
+   * @param Data rate to set for new default
+   */
+  static void SetDefaultRate(const DataRate&);
+
+  /** 
+   * Get the current default rate.
+   * @returns a const reference to current default
+   */
+
+  static const DataRate& GetDefaultRate();
+
 private:
   /**
    * Send a Packet Down the Wire.
@@ -223,39 +238,17 @@
   /**
    * Stop Sending a Packet Down the Wire and Begin the Interframe Gap.
    *
-   * The TransmitCompleteEvent method is used internally to finish the process
-   * of sending a packet out on the channel.  During execution of this method
-   * the TransmitEnd method is called on the channel to let it know that the
-   * physical device this class represents has virually finished sending 
-   * signals.  The channel uses this event to begin its speed of light delay
-   * timer after which it notifies the Net Device at the other end of the 
-   * link that the bits have arrived.  During this method, the net device 
-   * also schedules the TransmitReadyEvent at which time the transmitter 
-   * becomes ready to send the next packet.
+   * The TransmitComplete method is used internally to finish the process
+   * of sending a packet out on the channel.
    *
-   * @see PointToPointChannel::TransmitEnd ()
-   * @see TransmitReadyEvent ()
-   * @returns true if success, false on failure
    */
-  void TransmitCompleteEvent (void);
-  /**
-   * Cause the Transmitter to Become Ready to Send Another Packet.
-   *
-   * The TransmitReadyEvent method is used internally to re-enable the 
-   * transmit machine of the net device.  It is scheduled after a suitable
-   * interframe gap after the completion of the previous transmission.
-   * The queue is checked at this time, and if there is a packet waiting on
-   * the queue, the transmission process is begun.
-   *
-   * @see TransmitStart ()
-   */
-  void TransmitReadyEvent (void);
+  void TransmitComplete(void);
   /**
    * Create a Trace Resolver for events in the net device.
    *
    * @see class TraceResolver
    */
-  virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context);
+  virtual TraceResolver* DoCreateTraceResolver (TraceContext const &context);
   virtual bool DoNeedsArp (void) const;
   /**
    * Enumeration of the states of the transmit machine of the net device.
@@ -263,8 +256,7 @@
   enum TxMachineState
     {
       READY, /**< The transmitter is ready to begin transmission of a packet */
-      BUSY,  /**< The transmitter is busy transmitting a packet */
-      GAP    /**< The transmitter is in the interframe gap time */
+      BUSY   /**< The transmitter is busy transmitting a packet */
     };
   /**
    * The state of the Net Device transmit state machine.
@@ -305,6 +297,11 @@
    * @see class TraceResolver
    */
   CallbackTraceSource<Packet &> m_rxTrace;
+  /** 
+   * Default data rate.  Used for all newly created p2p net devices
+   */
+   static DataRateDefaultValue g_defaultRate;
+
 };
 
 }; // namespace ns3
--- a/src/node/mac-address.cc	Tue Jul 10 13:45:20 2007 +0100
+++ b/src/node/mac-address.cc	Fri Jul 13 10:40:10 2007 +0200
@@ -33,6 +33,9 @@
 
 namespace ns3 {
 
+// Static variables
+uint8_t MacAddress::g_nextAddress[MacAddress::MAX_LEN];
+
 static char
 AsciiToLowCase (char c)
 {
@@ -54,6 +57,13 @@
     }
 }
 
+MacAddress::MacAddress(uint8_t len) : m_len(len)
+{
+  NS_ASSERT (len <= MacAddress::MAX_LEN);
+  AdvanceAddress();
+  memcpy(m_address, g_nextAddress, len);
+}
+
 MacAddress::MacAddress (uint8_t const *address, uint8_t len)
 {
   NS_ASSERT (len <= MacAddress::MAX_LEN);
@@ -148,6 +158,17 @@
         m_len = len;
 }
 
+// Static methods
+void MacAddress::AdvanceAddress()
+  {
+    // Advance to next address, little end first
+    for(size_t i = 0; i < MAX_LEN; ++i)
+      {
+        if (++g_nextAddress[i] != 0) break;
+      }
+  }
+
+// Non-member operators
 bool operator == (MacAddress const&a, MacAddress const&b)
 {
 	return a.IsEqual (b);
--- a/src/node/mac-address.h	Tue Jul 10 13:45:20 2007 +0100
+++ b/src/node/mac-address.h	Fri Jul 13 10:40:10 2007 +0200
@@ -47,6 +47,13 @@
    */
   MacAddress (void);
   /**
+   * \brief Construct a MacAddress using the next available
+   * address.
+   * \see MacAddres::Next
+   * \param len length, in bytes, of the desired address
+   */
+  MacAddress(uint8_t len);
+  /**
    * \brief Construct a MacAddress from a byte-array
    *
    * low byte should be first.
@@ -97,6 +104,14 @@
    */
   void Set (uint8_t const ad[MAX_LEN], uint8_t len);
 
+  // Static methods/members
+  /**
+   *
+   * Advance the global to the next available mac address.
+   */
+  static void AdvanceAddress();
+  static uint8_t g_nextAddress[MAX_LEN];
+
 private:
   uint8_t m_address[MAX_LEN];
   uint8_t m_len;
--- a/src/simulator/simulator.h	Tue Jul 10 13:45:20 2007 +0100
+++ b/src/simulator/simulator.h	Fri Jul 13 10:40:10 2007 +0200
@@ -173,6 +173,10 @@
    */
   template <typename T, typename OBJ, typename T1>
   static EventId Schedule (Time const &time, void (T::*mem_ptr) (T1), OBJ obj, T1 a1);
+  template <typename T, typename OBJ, typename T1>
+  static EventId Schedule (Time const &time, void (T::*mem_ptr) (const T1&), OBJ obj, T1 a1); // GFR
+  template <typename T, typename OBJ, typename T1>
+  static EventId Schedule (Time const &time, void (T::*mem_ptr) (T1&), OBJ obj, T1 a1); // GFR
   /**
    * @param time the relative expiration time of the event.
    * @param mem_ptr member method pointer to invoke
@@ -234,6 +238,10 @@
    */
   template <typename T1>
   static EventId Schedule (Time const &time, void (*f) (T1), T1 a1);
+  template <typename T1>
+  static EventId Schedule (Time const &time, void (*f) (const T1&), T1 a1); // GFR
+  template <typename T1>
+  static EventId Schedule (Time const &time, void (*f) (T1&), T1 a1); // GFR
   /**
    * @param time the relative expiration time of the event.
    * @param f the function to invoke
@@ -533,6 +541,10 @@
   static EventImpl *MakeEvent (void (T::*mem_ptr) (void), OBJ obj);
   template <typename T, typename OBJ, typename T1>
   static EventImpl *MakeEvent (void (T::*mem_ptr) (T1), OBJ obj, T1 a1);
+  template <typename T, typename OBJ, typename T1>
+  static EventImpl *MakeEvent (void (T::*mem_ptr) (const T1&), OBJ obj, T1 a1); // GFR
+  template <typename T, typename OBJ, typename T1>
+  static EventImpl *MakeEvent (void (T::*mem_ptr) (T1&), OBJ obj, T1 a1); // GFR
   template <typename T, typename OBJ, typename T1, typename T2>
   static EventImpl *MakeEvent (void (T::*mem_ptr) (T1,T2), OBJ obj, T1 a1, T2 a2);
   template <typename T, typename OBJ, typename T1, typename T2, typename T3>
@@ -642,6 +654,56 @@
   return ev;
 }
 
+template <typename T, typename OBJ, typename T1>
+EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (const T1&), OBJ obj, T1 a1) 
+{
+  // one argument version, with const reference
+  class EventMemberImpl1 : public EventImpl {
+  public:
+    typedef void (T::*F)(const T1&);
+    EventMemberImpl1 (OBJ obj, F function, T1 a1) 
+      : m_obj (obj), 
+        m_function (function),
+        m_a1 (a1)
+    {}
+  protected:
+    virtual ~EventMemberImpl1 () {}
+  private:
+    virtual void Notify (void) { 
+      (EventMemberImplTraits<OBJ>::GetReference (m_obj).*m_function) (m_a1);
+    }
+    OBJ m_obj;
+    F m_function;
+    T1 m_a1;
+  } *ev = new EventMemberImpl1 (obj, mem_ptr, a1);
+  return ev;
+}
+
+template <typename T, typename OBJ, typename T1>
+EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (T1&), OBJ obj, T1 a1) 
+{
+  // one argument version with non-const reference
+  class EventMemberImpl1 : public EventImpl {
+  public:
+    typedef void (T::*F)(T1&);
+    EventMemberImpl1 (OBJ obj, F function, T1 a1) 
+      : m_obj (obj), 
+        m_function (function),
+        m_a1 (a1)
+    {}
+  protected:
+    virtual ~EventMemberImpl1 () {}
+  private:
+    virtual void Notify (void) { 
+      (EventMemberImplTraits<OBJ>::GetReference (m_obj).*m_function) (m_a1);
+    }
+    OBJ m_obj;
+    F m_function;
+    T1 m_a1;
+  } *ev = new EventMemberImpl1 (obj, mem_ptr, a1);
+  return ev;
+}
+
 template <typename T, typename OBJ, typename T1, typename T2>
 EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (T1,T2), OBJ obj, T1 a1, T2 a2) 
 {
@@ -920,6 +982,18 @@
   return Schedule (time, MakeEvent (mem_ptr, obj, a1));
 }
 
+template <typename T, typename OBJ, typename T1>
+EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (const T1&), OBJ obj, T1 a1) 
+{
+  return Schedule (time, MakeEvent (mem_ptr, obj, a1));
+}
+
+template <typename T, typename OBJ, typename T1>
+EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (T1&), OBJ obj, T1 a1) 
+{
+  return Schedule (time, MakeEvent (mem_ptr, obj, a1));
+}
+
 template <typename T, typename OBJ, typename T1, typename T2>
 EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (T1,T2), OBJ obj, T1 a1, T2 a2) 
 {