merge with ns-3-dev
authorGustavo J. A. M. Carneiro <gjc@inescporto.pt>
Wed, 12 Sep 2007 18:06:09 +0100
changeset 1744 d658b8810b5a
parent 1743 0a84462bb582 (current diff)
parent 1493 149976da3ab6 (diff)
child 1745 0e8301827889
merge with ns-3-dev
examples/wscript
src/internet-node/ipv4-l3-protocol.cc
--- a/.hgtags	Tue Sep 11 15:09:55 2007 +0100
+++ b/.hgtags	Wed Sep 12 18:06:09 2007 +0100
@@ -4,3 +4,4 @@
 38099dd26e9467b8f49f8632f22789858149a6e7 release ns-3.0.3
 5701e60bf01a8ac1308945e69001e0cc07948faf release ns-3.0.4
 08046b6aef37932507696a2f2f427b42d693781e release ns-3.0.5
+267e2ebc28e4e4ae2f579e1cfc29902acade0c34 buffer-working-before-breaking
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/README.multicast-routing	Wed Sep 12 18:06:09 2007 +0100
@@ -0,0 +1,235 @@
+Static multicast routing overview
+--------------------------------
+
+This is brief documentation of a proposal to add static multicast
+routing to ns-3.
+
+This extension allows the simulation user to:
+
+- manually add Ipv4 multicast routes to a router
+- specify a default outgoing interface for multicast sources (hosts) in 
+  various ways
+- allow a multicast receiver (hosts) to join a multicast group, to enable
+  reception of that group's datagrams
+
+1.  Code location:
+
+- http://code.nsnam.org/craigdo/ns-3-mc
+
+- the main source code is found in src/internet-node/ipv4-static-routing.{cc,h}
+
+also touched are:
+- src/internet-node/ipv4-l3-protocol.cc (forwarding methods for the
+  static routing API)
+- src/node/net-device.cc (provides virtual NetDevice::MakeMulticastAddress)
+- src/arp-ipv4-interface.cc (calls NetDevice::MakeMulticastAddress)
+- src/devices/csma/csma-net-device.cc (handles multicast addressing and
+  reception).
+- src/devices/point-to-point/point-to-point-net-device.cc (implements required
+  virtual methods.
+- src/internet-node/ (several files have added tracing)
+ 
+- a heavily commented example script is in examples/csma-multicast.cc
+
+2.  API:
+
+The API for adding a multicast route is:
+
+/**
+ * @brief Add a multicast route to the static routing table.
+ *
+ * A multicast route must specify an origin IP address, a multicast group and
+ * an input network interface index as conditions and provide a vector of
+ * output network interface indices over which packets matching the conditions
+ * are sent.
+ *
+ * Typically there are two main types of multicast routes:  routes of the 
+ * first kind are used during forwarding.  All of the conditions must be
+ * exlicitly provided.  The second kind of routes are used to get packets off
+ * of a local node.  The difference is in the input interface.  Routes for
+ * forwarding will always have an explicit input interface specified.  Routes
+ * off of a node will always set the input interface to a wildcard specified
+ * by the index Ipv4RoutingProtocol::IF_INDEX_ANY.
+ *
+ * For routes off of a local node wildcards may be used in the origin and
+ * multicast group addresses.  The wildcard used for Ipv4Adresses is that 
+ * address returned by Ipv4Address::GetAny () -- typically "0.0.0.0".  Usage
+ * of a wildcard allows one to specify default behavior to varying degrees.
+ *
+ * For example, making the origin address a wildcard, but leaving the 
+ * multicast group specific allows one (in the case of a node with multiple
+ * interfaces) to create different routes using different output interfaces
+ * for each multicast group.
+ *
+ * If the origin and multicast addresses are made wildcards, you have created
+ * essentially a default multicast address that can forward to multiple 
+ * interfaces.  Compare this to the actual default multicast address that is
+ * limited to specifying a single output interface for compatibility with
+ * existing functionality in other systems.
+ * 
+ * @param origin The Ipv4Address of the origin of packets for this route.  May
+ * be Ipv4Address:GetAny for open groups.
+ * @param group The Ipv4Address of the multicast group or this route.
+ * @param inputInterface The input network interface index over which to 
+ * expect packets destined for this route.  May be
+ * Ipv4RoutingProtocol::IF_INDEX_ANY for packets of local origin.
+ * @param outputInterface A vector of network interface indices used to specify
+ * how to send packets to the destination(s).
+ *
+ * @see Ipv4Address
+ */
+  Ipv4::AddMulticastRoute (Ipv4Address origin,
+	                   Ipv4Address group,
+                           uint32_t inputInterface,
+                           std::vector<uint32_t> outputInterfaces)
+
+To remove a route, one uses:
+
+/**
+ * @brief Remove a route from the static multicast routing table.
+ *
+ * Externally, the multicast static routing table appears simply as a table 
+ * with n entries.  The one sublety of note is that if a default multicast
+ * route has been set it will appear as the zeroth entry in the table.  This
+ * means that the default route may be removed by calling this method with
+ * appropriate wildcard parameters.
+ *
+ * This method causes the multicast routing table to be searched for the first
+ * route that matches the parameters and removes it.
+ *
+ * Wildcards may be provided to this function, but the wildcards are used to
+ * exacly match wildcards in the routes (see AddMulticastRoute).  That is,
+ * calling RemoveMulticastRoute with the origin set to "0.0.0.0" will not
+ * remove routes with any address in the origin, but will only remove routes
+ * with "0.0.0.0" set as the the origin.
+ *
+ * @param origin The IP address specified as the origin of packets for the
+ * route.
+ * @param origin The IP address specified as the multicast group addres of
+ * the route.
+ * @param inputInterfade The network interface index specified as the expected
+ * input interface for the route.
+ * @returns True if a route was found and removed, false otherwise.
+ *
+ * @see Ipv4MulticastRoute
+ * @see Ipv4StaticRouting::AddMulticastRoute
+ */
+  Ipv4::RemoveMulticastRoute (Ipv4Address origin,
+                              Ipv4Address group,
+                              uint32_t inputInterface)
+
+For symmetry with the unicast routing interface, a method is provided to 
+remove routes by index:
+
+/**
+ * @brief Remove a route from the static multicast routing table.
+ *
+ * Externally, the multicast static routing table appears simply as a table 
+ * with n entries.  The one sublety of note is that if a default multicast
+ * route has been set it will appear as the zeroth entry in the table.  This 
+ * means that if the default route has been set, calling 
+ * RemoveMulticastRoute (0) will remove the default route.
+ *
+ * @param index The index (into the multicast routing table) of the route to
+ * remove.  If the default route has been set, it will occupy index zero.
+ *
+ * @see Ipv4Route
+ * @see Ipv4StaticRouting::GetRoute
+ * @see Ipv4StaticRouting::AddRoute
+ */
+  void RemoveMulticastRoute (uint32_t index);
+
+For compatibility, and to provide simplicity, one can set a default multicast
+route for a host originating data:
+
+/**
+ * @brief Add a default multicast route to the static routing table.
+ *
+ * This is the multicast equivalent of the unicast version SetDefaultRoute.
+ * We tell the routing system what to do in the case where a specific route
+ * to a destination multicast group is not found.  The system forwards 
+ * packets out the specified interface in the hope that "something out there"
+ * knows better how to route the packet.  This method is only used in 
+ * initially sending packets off of a host.  The default multicast route is
+ * not consulted during forwarding -- exact routes must be specified using
+ * AddMulticastRoute for that case.
+ *
+ * Since we're basically sending packets to some entity we think may know
+ * better what to do, we don't pay attention to "subtleties" like origin
+ * address, nor do we worry about forwarding out multiple  interfaces.  If the
+ * default multicast route is set, it is returned as the selected route from 
+ * LookupStatic irrespective of origin or multicast group if another specific
+ * route is not found.
+ *
+ * @param outputInterface The network interface index used to specify where
+ * to send packets in the case of unknown routes.
+ *
+ * @see Ipv4Address
+ */
+  Ipv4::SetDefaultMulticastRoute (uint32_t outputInterface)
+
+For a host wanting to receive multicast data, the following function is used
+to join each multicast group.
+
+  /**
+   * \brief Join a multicast group for a given multicast source and 
+   *        group.
+   *
+   * \param origin The Ipv4 address of the multicast source.
+   * \param group The multicast group address.
+   */
+  Ipv4::JoinMulticastGroup (Ipv4Address origin, Ipv4Address group);
+
+To stop receiving multicast data, the following function is used:
+
+  /**
+   * \brief Leave a multicast group for a given multicast source and 
+   *        group.
+   *
+   * \param origin The Ipv4 address of the multicast source.
+   * \param group The multicast group address.
+   */
+   LeaveMulticastGroup (Ipv4Address origin, Ipv4Address group);
+
+There are new lookup functions implemented in Ipv4:
+
+  /**
+   * \brief Find and return the interface ID of the interface that has been
+   *        assigned the specified IP address.
+   * \param addr The IP address assigned to the interface of interest.
+   * \returns The index of the ipv4 interface with the given address.
+   *
+   * Each IP interface has an IP address associated with it.  It is often 
+   * useful to search the list of interfaces for one that corresponds to 
+   * a known IP Address.  This call takes an IP address as a parameter and
+   * returns the interface index of the first interface that has been assigned
+   * that address.  If the address is not found, this function asserts.
+   */
+  Ipv4::FindInterfaceForAddr (Ipv4Address addr) const;
+
+  /**
+   * \brief Find and return the interface ID of the interface that has been
+   *        assigned the specified (masked) IP address.
+   * \param addr The IP address assigned to the interface of interest.
+   * \param mask The address mask to be used in address matching.
+   * \returns The index of the ipv4 interface with the given address.
+   *
+   * Each IP interface has an IP address associated with it.  It is often 
+   * useful to search the list of interfaces for one that corresponds to 
+   * a known IP Address.  This call takes an IP address and an IP address
+   * mask as parameters and returns the interface index of the first interface
+   * that matches the masked IP address.
+   */
+   Ipv4::FindInterfaceForAddr (Ipv4Address addr, Ipv4Mask mask) const;
+
+Also, there are various methods to lookup and iterate the static multicast
+routes of a node, in the Ipv4StaticRouting class.
+
+3.  Dependencies:
+
+- fix for bug 69 (source Ipv4 address is set correctly for UDP)
+- fix for OnOffApplication that receives data
+
+4.  Open issues or features not included
+
+- choose source interface on a per-group basis when a host is multihomed
--- a/examples/csma-broadcast.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/examples/csma-broadcast.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -66,13 +66,24 @@
 
   // Users may find it convenient to turn on explicit debugging
   // for selected modules; the below lines suggest how to do this
-#if 0 
+#if 0
+  DebugComponentEnable("Object");
+  DebugComponentEnable("Queue");
+  DebugComponentEnable("DropTailQueue");
+  DebugComponentEnable("Channel");
+  DebugComponentEnable("CsmaChannel");
+  DebugComponentEnable("NetDevice");
   DebugComponentEnable("CsmaNetDevice");
   DebugComponentEnable("Ipv4L3Protocol");
-  DebugComponentEnable("NetDevice");
-  DebugComponentEnable("Channel");
-  DebugComponentEnable("CsmaChannel");
+  DebugComponentEnable("OnOffApplication");
   DebugComponentEnable("PacketSocket");
+  DebugComponentEnable("UdpSocket");
+  DebugComponentEnable("UdpL4Protocol");
+  DebugComponentEnable("Ipv4L3Protocol");
+  DebugComponentEnable("Ipv4StaticRouting");
+  DebugComponentEnable("Ipv4Interface");
+  DebugComponentEnable("ArpIpv4Interface");
+  DebugComponentEnable("Ipv4LoopbackInterface");
 #endif
 
   // Set up some default values for the simulation.  Use the Bind()
@@ -103,13 +114,13 @@
     CsmaTopology::CreateCsmaChannel(
       DataRate(5000000), MilliSeconds(2));
 
-  uint32_t n0ifIndex0 = CsmaIpv4Topology::AddIpv4CsmaNode (n0, channel0, 
+  uint32_t n0ifIndex0 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n0, channel0, 
                                          Eui48Address("10:54:23:54:0:50"));
-  uint32_t n0ifIndex1 = CsmaIpv4Topology::AddIpv4CsmaNode (n0, channel1, 
+  uint32_t n0ifIndex1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n0, channel1, 
                                          Eui48Address("10:54:23:54:0:51"));
-  uint32_t n1ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n1, channel0,
+  uint32_t n1ifIndex = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n1, channel0,
                                          Eui48Address("10:54:23:54:23:51"));
-  uint32_t n2ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n2, channel1,
+  uint32_t n2ifIndex = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, channel1,
                                          Eui48Address("10:54:23:54:23:52"));
 
   // Later, we add IP addresses.  
@@ -125,6 +136,18 @@
   CsmaIpv4Topology::AddIpv4Address (
       n2, n2ifIndex, Ipv4Address("192.168.1.2"), Ipv4Mask("255.255.255.0"));
 
+  // XXX Is this the right thing to do?
+  //
+  // The OnOff application uses a connected socket.  This socket needs to be
+  // able to figure out which interface to use as the source address for
+  // packets.  When there's one interface, this isn't too hard, but node zero
+  // has two interfaces, and limited broadcasts will be sent out both of those
+  // interfaces.  We need to provide some way to disambiguate the choice.
+  // If we supply a default route, the specified interface will be chosen.
+
+  Ptr<Ipv4> ipv4 = n0->QueryInterface<Ipv4> (Ipv4::iid);
+  ipv4->SetDefaultRoute ("192.168.1.3", n0ifIndex0);
+
   // Create the OnOff application to send UDP datagrams of size
   // 210 bytes at a rate of 448 Kb/s
   // from n0 to n1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/csma-multicast.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -0,0 +1,312 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * 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
+ */
+
+// Network topology
+//
+//                     Lan1
+//                 ===========
+//                 |    |    | 
+//       n0   n1   n2   n3   n4
+//       |    |    |
+//       ===========
+//           Lan0
+//
+// - Multicast source is at node n0;
+// - Multicast forwarded by node n2 onto LAN1;
+// - Nodes n0, n1, n2, n3, and n4 receive the multicast frame.
+// - Node n4 listens for the data (actual listener not yet implementted)
+
+#include "ns3/command-line.h"
+#include "ns3/default-value.h"
+#include "ns3/ptr.h"
+#include "ns3/random-variable.h"
+#include "ns3/debug.h"
+#include "ns3/simulator.h"
+#include "ns3/nstime.h"
+#include "ns3/data-rate.h"
+#include "ns3/ascii-trace.h"
+#include "ns3/pcap-trace.h"
+#include "ns3/internet-node.h"
+#include "ns3/csma-channel.h"
+#include "ns3/csma-net-device.h"
+#include "ns3/csma-topology.h"
+#include "ns3/csma-ipv4-topology.h"
+#include "ns3/eui48-address.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/inet-socket-address.h"
+#include "ns3/ipv4.h"
+#include "ns3/socket.h"
+#include "ns3/ipv4-route.h"
+#include "ns3/onoff-application.h"
+
+using namespace ns3;
+
+NS_DEBUG_COMPONENT_DEFINE ("CsmaMulticast");
+
+int 
+main (int argc, char *argv[])
+{
+//
+// Users may find it convenient to turn on explicit debugging
+// for selected modules; the below lines suggest how to do this
+//
+#if 0
+  DebugComponentEnable("CsmaMulticast");
+
+  DebugComponentEnable("Object");
+  DebugComponentEnable("Queue");
+  DebugComponentEnable("DropTailQueue");
+  DebugComponentEnable("Channel");
+  DebugComponentEnable("CsmaChannel");
+  DebugComponentEnable("NetDevice");
+  DebugComponentEnable("CsmaNetDevice");
+  DebugComponentEnable("Ipv4L3Protocol");
+  DebugComponentEnable("OnOffApplication");
+  DebugComponentEnable("PacketSocket");
+  DebugComponentEnable("UdpSocket");
+  DebugComponentEnable("UdpL4Protocol");
+  DebugComponentEnable("Ipv4L3Protocol");
+  DebugComponentEnable("Ipv4StaticRouting");
+  DebugComponentEnable("Ipv4Interface");
+  DebugComponentEnable("ArpIpv4Interface");
+  DebugComponentEnable("Ipv4LoopbackInterface");
+#endif
+
+//
+// Set up default values for the simulation.  Use the DefaultValue::Bind()
+// technique to tell the system what subclass of Queue to use.  The Bind
+// command command tells the queue factory which class to instantiate when the
+// queue factory is invoked in the topology code
+//
+  DefaultValue::Bind ("Queue", "DropTailQueue");
+//
+// Allow the user to override any of the defaults and the above Bind() at
+// run-time, via command-line arguments
+//
+  CommandLine::Parse (argc, argv);
+//
+// Explicitly create the nodes required by the topology (shown above).
+//
+  NS_DEBUG("Create nodes.");
+  Ptr<Node> n0 = Create<InternetNode> ();
+  Ptr<Node> n1 = Create<InternetNode> (); 
+  Ptr<Node> n2 = Create<InternetNode> (); 
+  Ptr<Node> n3 = Create<InternetNode> ();
+  Ptr<Node> n4 = Create<InternetNode> ();
+
+  NS_DEBUG("Create channels.");
+//
+// Explicitly create the channels required by the topology (shown above).
+//
+  Ptr<CsmaChannel> lan0 = 
+    CsmaTopology::CreateCsmaChannel(DataRate(5000000), MilliSeconds(2));
+
+  Ptr<CsmaChannel> lan1 = 
+    CsmaTopology::CreateCsmaChannel(DataRate(5000000), MilliSeconds(2));
+
+  NS_DEBUG("Build Topology.");
+//
+// Now fill out the topology by creating the net devices required to connect
+// the nodes to the channels and hooking them up.  AddIpv4CsmaNetDevice will
+// create a net device, add a MAC address (in memory of the pink flamingo) and
+// connect the net device to a nodes and also to a channel. the 
+// AddIpv4CsmaNetDevice method returns a net device index for the net device
+// created on the node.  Interpret nd0 as the net device we created for node
+// zero.  Interpret nd2Lan0 as the net device we created for node two to
+// connect to Lan0. 
+//
+  uint32_t nd0 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n0, lan0, 
+    Eui48Address("08:00:2e:00:00:00"));
+  uint32_t nd1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n1, lan0, 
+    Eui48Address("08:00:2e:00:00:01"));
+  uint32_t nd2Lan0 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, lan0, 
+    Eui48Address("08:00:2e:00:00:02"));
+
+  uint32_t nd2Lan1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, lan1, 
+    Eui48Address("08:00:2e:00:00:03"));
+  uint32_t nd3 __attribute__ ((unused)) = 
+    CsmaIpv4Topology::AddIpv4CsmaNetDevice (n3, lan1, 
+    Eui48Address("08:00:2e:00:00:04"));
+  uint32_t nd4 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n4, lan1, 
+    Eui48Address("08:00:2e:00:00:05"));
+
+  NS_DEBUG ("nd0 = " << nd0);
+  NS_DEBUG ("nd1 = " << nd1);
+  NS_DEBUG ("nd2Lan0 = " << nd2Lan0);
+  NS_DEBUG ("nd2Lan1 = " << nd2Lan1);
+  NS_DEBUG ("nd3 = " << nd3);
+  NS_DEBUG ("nd4 = " << nd3);
+//
+// We've got the "hardware" in place.  Now we need to add IP addresses.
+//
+  NS_DEBUG("Assign IP Addresses.");
+
+  CsmaIpv4Topology::AddIpv4Address (n0, nd0, Ipv4Address ("10.1.1.1"), 
+    Ipv4Mask ("255.255.255.0"));
+
+  CsmaIpv4Topology::AddIpv4Address (n1, nd1, Ipv4Address ("10.1.1.2"), 
+    Ipv4Mask ("255.255.255.0"));
+
+//
+// We'll need these addresses later
+//
+  Ipv4Address n2Lan0Addr ("10.1.1.3");
+  Ipv4Address n2Lan1Addr ("10.1.2.1");
+
+  CsmaIpv4Topology::AddIpv4Address (n2, nd2Lan0, n2Lan0Addr, 
+    Ipv4Mask ("255.255.255.0"));
+//
+// Assign IP addresses to the net devices and associated interfaces on Lan1
+//
+  CsmaIpv4Topology::AddIpv4Address (n2, nd2Lan1, n2Lan1Addr, 
+    Ipv4Mask ("255.255.255.0"));
+
+  CsmaIpv4Topology::AddIpv4Address (n3, nd1, Ipv4Address ("10.1.2.2"), 
+    Ipv4Mask ("255.255.255.0"));
+
+  CsmaIpv4Topology::AddIpv4Address (n4, nd4, Ipv4Address ("10.1.2.3"), 
+    Ipv4Mask ("255.255.255.0"));
+
+  NS_DEBUG("Configure multicasting.");
+//
+// Now we can configure multicasting.  As described above, the multicast 
+// source is at node zero, which we assigned the IP address of 10.1.1.1 
+// earlier.  We need to define a multicast group to send packets to.  This
+// can be any multicast address from 224.0.0.0 through 239.255.255.255
+// (avoiding the reserved routing protocol addresses).  We just pick a
+// convenient number (225.0.0.0) and or in some bits to let us verify that
+// correct Ethernet multicast addresses are constructed down in the system. 
+//
+  Ipv4Address multicastSource ("10.1.1.1");
+  Ipv4Address multicastGroup ("225.1.2.4");
+//
+// We are going to manually configure multicast routing.  This means telling
+// node two that it should expect multicast data coming from IP address 
+// 10.1.1.1 originally.  It should expect these data coming in over its IP 
+// interface connected to Lan0.  When node two receives these packets, they
+// should be forwarded out the interface that connects it to Lan1.
+//
+// We're going to need the interface indices on node two corresponding to 
+// these interfaces, which we call ifIndexLan0 and ifIndexLan1.  The most
+// general way to get these interfaces is to look them up by IP address.
+// Looking back to the topology creation calls above, we saved the addresses
+// assigned to the interface connecting node two to Lan0 and Lan1.  Now is
+// a fine time to find the interface indices on node two.
+//
+  Ptr<Ipv4> ipv4;
+  ipv4 = n2->QueryInterface<Ipv4> (Ipv4::iid);
+
+  uint32_t ifIndexLan0 = ipv4->FindInterfaceForAddr (n2Lan0Addr);
+  uint32_t ifIndexLan1 = ipv4->FindInterfaceForAddr (n2Lan1Addr);
+//
+// Now, we need to do is to call the AddMulticastRoute () method on node 
+// two's Ipv4 interface and tell it that whenever it receives a packet on
+// the interface from Lan0, with the packet from the multicast source, 
+// destined for the multicast group, it should forward these packets down
+// the interface connecting it to Lan1.  (Note: the vector of output
+// interfaces is in case there are multiple net devices on a node -- not
+// true in this case).
+//
+  std::vector<uint32_t> outputInterfaces (1);
+  outputInterfaces[0] = ifIndexLan1;
+
+  ipv4->AddMulticastRoute (multicastSource, multicastGroup, ifIndexLan0,
+    outputInterfaces);
+//
+// We need to specify how the source node handles multicasting.  There are a
+// number of ways we can deal with this, we just need to pick one.  The first
+// method is to add an explicit route out of the source node, just as we did
+// for the forwarding node.  Use this method when you want to send packets out
+// multiple interfaces or send packets out different interfaces based on the
+// differing multicast groups.  Since the source is local, there will be no 
+// input interface over which packets are received, so use  
+// Ipv4RoutingProtocol::IF_INDEX_ANY as a wildcard.
+//
+// A second way is to specify a multicast route using wildcards.  If you 
+// want to send multicasts out differing sets of interfaces based on the 
+// multicast group, you can use AddMulticastRoute () but specify the origin 
+// as a wildcard.  If you want all multicasts to go out a single set of 
+// interfaces, you can make both the origin and group a wildcard.
+//
+// If you have a simple system, where the source has a single interface, this
+// can be done via the SetDefaultMulticastRoute () method on the Ipv4 
+// interface.  This tells the system to send all multicasts out a single
+// specified network interface index.
+//
+// A last way is to specify a (or use an existing) default unicast route.  The
+// multicast routing code uses the unicast default route as a multicast "route
+// of last resort."  this method for is also on Ipv4 and is called 
+// SetDefaultRoute ().
+//
+// Since this is a simple multicast example, we use the 
+// SetDefaultMulticastRoute () approach.  We are going to first need the 
+// Ipv4 interface for node 0 which is the multicast source.  We use this
+// interface to find the output interface index, and tell node zero to send
+// its multicast traffic out that interface.
+//
+  ipv4 = n0->QueryInterface<Ipv4> (Ipv4::iid);
+  uint32_t ifIndexSrc = ipv4->FindInterfaceForAddr (multicastSource);
+  ipv4->SetDefaultMulticastRoute (ifIndexSrc);
+//
+// As described above, node four will be the only node listening for the
+// multicast data.  To enable forwarding bits up the protocol stack, we need
+// to tell the stack to join the multicast group.
+//
+  ipv4 = n4->QueryInterface<Ipv4> (Ipv4::iid);
+  ipv4->JoinMulticastGroup (multicastSource, multicastGroup);
+//
+// Create an OnOff application to send UDP datagrams from node zero to the
+// multicast group (node four will be listening).
+//
+  NS_DEBUG("Create Applications.");
+  Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
+    n0, 
+    InetSocketAddress (multicastGroup, 80), 
+    "Udp",
+    ConstantVariable(1), 
+    ConstantVariable(0),
+    DataRate ("255b/s"),
+    128);
+//
+// Tell the application when to start and stop.
+//
+  ooff->Start(Seconds(1.));
+  ooff->Stop (Seconds(10.));
+//
+// Configure tracing of all enqueue, dequeue, and NetDevice receive events.
+// Trace output will be sent to the file "csma-multicast.tr"
+//
+  NS_DEBUG("Configure Tracing.");
+  AsciiTrace asciitrace ("csma-multicast.tr");
+  asciitrace.TraceAllNetDeviceRx ();
+  asciitrace.TraceAllQueues ();
+//
+// Also configure some tcpdump traces; each interface will be traced.
+// The output files will be named:
+//     csma-multicast.pcap-<nodeId>-<interfaceId>
+// and can be read by the "tcpdump -r" command (use "-tt" option to
+// display timestamps correctly)
+//
+  PcapTrace pcaptrace ("csma-multicast.pcap");
+  pcaptrace.TraceAllIp ();
+//
+// Now, do the actual simulation.
+//
+  NS_DEBUG("Run Simulation.");
+  Simulator::Run ();
+  Simulator::Destroy ();
+  NS_DEBUG("Done.");
+}
--- a/examples/csma-one-subnet.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/examples/csma-one-subnet.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -14,35 +14,25 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-// Port of ns-2/tcl/ex/simple.tcl to ns-3
-//
 // Network topology
 //
 //       n0    n1   n2   n3
 //       |     |    |    |
-//     =====================
+//       =================
+//              LAN
 //
-// - CBR/UDP flows from n0 to n1, and from n3 to n0
-// - UDP packet size of 210 bytes, with per-packet interval 0.00375 sec.
-//   (i.e., DataRate of 448,000 bps)
+// - CBR/UDP flows from n0 to n1 and from n3 to n0
 // - DropTail queues 
 // - Tracing of queues and packet receptions to file "csma-one-subnet.tr"
 
-#include <iostream>
-#include <fstream>
-#include <string>
-#include <cassert>
-
 #include "ns3/command-line.h"
 #include "ns3/default-value.h"
 #include "ns3/ptr.h"
 #include "ns3/random-variable.h"
 #include "ns3/debug.h"
-
 #include "ns3/simulator.h"
 #include "ns3/nstime.h"
 #include "ns3/data-rate.h"
-
 #include "ns3/ascii-trace.h"
 #include "ns3/pcap-trace.h"
 #include "ns3/internet-node.h"
@@ -58,109 +48,168 @@
 #include "ns3/ipv4-route.h"
 #include "ns3/onoff-application.h"
 
-
 using namespace ns3;
 
-
-int main (int argc, char *argv[])
-{
+NS_DEBUG_COMPONENT_DEFINE ("CsmaOneSubnet");
 
-  // Users may find it convenient to turn on explicit debugging
-  // for selected modules; the below lines suggest how to do this
+int 
+main (int argc, char *argv[])
+{
+//
+// Users may find it convenient to turn on explicit debugging
+// for selected modules; the below lines suggest how to do this
+//
 #if 0 
+  DebugComponentEnable("CsmaOneSubnet");
+
+  DebugComponentEnable("Object");
+  DebugComponentEnable("Queue");
+  DebugComponentEnable("DropTailQueue");
+  DebugComponentEnable("Channel");
+  DebugComponentEnable("CsmaChannel");
   DebugComponentEnable("CsmaNetDevice");
   DebugComponentEnable("Ipv4L3Protocol");
   DebugComponentEnable("NetDevice");
-  DebugComponentEnable("Channel");
-  DebugComponentEnable("CsmaChannel");
   DebugComponentEnable("PacketSocket");
+  DebugComponentEnable("OnOffApplication");
+  DebugComponentEnable("UdpSocket");
+  DebugComponentEnable("UdpL4Protocol");
+  DebugComponentEnable("Ipv4L3Protocol");
+  DebugComponentEnable("Ipv4StaticRouting");
+  DebugComponentEnable("Ipv4Interface");
+  DebugComponentEnable("ArpIpv4Interface");
+  DebugComponentEnable("Ipv4LoopbackInterface");
 #endif
-
-  // Set up some default values for the simulation.  Use the Bind()
-  // technique to tell the system what subclass of Queue to use,
-  // and what the queue limit is
-
-  // The below Bind command tells the queue factory which class to
-  // instantiate, when the queue factory is invoked in the topology code
+//
+// Set up default values for the simulation.  Use the DefaultValue::Bind()
+// technique to tell the system what subclass of Queue to use.  The Bind
+// command command tells the queue factory which class to instantiate when the
+// queue factory is invoked in the topology code
+//
   DefaultValue::Bind ("Queue", "DropTailQueue");
-
-  // Allow the user to override any of the defaults and the above
-  // Bind()s at run-time, via command-line arguments
+//
+// Allow the user to override any of the defaults and the above Bind() at
+// run-time, via command-line arguments
+//
   CommandLine::Parse (argc, argv);
-
-  // Here, we will explicitly create four nodes.  In more sophisticated
-  // topologies, we could configure a node factory.
+//
+// Explicitly create the nodes required by the topology (shown above).
+//
+  NS_DEBUG("Create nodes.");
   Ptr<Node> n0 = Create<InternetNode> ();
   Ptr<Node> n1 = Create<InternetNode> (); 
   Ptr<Node> n2 = Create<InternetNode> (); 
   Ptr<Node> n3 = Create<InternetNode> ();
 
-  // We create the channels first without any IP addressing information
-  Ptr<CsmaChannel> channel0 = 
-    CsmaTopology::CreateCsmaChannel(
-      DataRate(5000000), MilliSeconds(2));
+  NS_DEBUG("Create channels.");
+//
+// Explicitly create the channels required by the topology (shown above).
+//
+  Ptr<CsmaChannel> lan = CsmaTopology::CreateCsmaChannel(
+    DataRate(5000000), MilliSeconds(2));
 
-  uint32_t n0ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n0, channel0, 
-                                         Eui48Address("10:54:23:54:23:50"));
-  uint32_t n1ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n1, channel0,
-                                         Eui48Address("10:54:23:54:23:51"));
-  uint32_t n2ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n2, channel0,
-                                         Eui48Address("10:54:23:54:23:52"));
-  uint32_t n3ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n3, channel0,
-                                         Eui48Address("10:54:23:54:23:53"));
+  NS_DEBUG("Build Topology.");
+//
+// Now fill out the topology by creating the net devices required to connect
+// the nodes to the channels and hooking them up.  AddIpv4CsmaNetDevice will
+// create a net device, add a MAC address (in memory of the pink flamingo) and
+// connect the net device to a nodes and also to a channel. the 
+// AddIpv4CsmaNetDevice method returns a net device index for the net device
+// created on the node.  Interpret nd0 as the net device we created for node
+// zero.
+//
+  uint32_t nd0 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n0, lan, 
+    Eui48Address("08:00:2e:00:00:00"));
+
+  uint32_t nd1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n1, lan, 
+    Eui48Address("08:00:2e:00:00:01"));
+
+  uint32_t nd2 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, lan, 
+    Eui48Address("08:00:2e:00:00:02"));
+
+  uint32_t nd3 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n3, lan, 
+    Eui48Address("08:00:2e:00:00:03"));
 
-  // Later, we add IP addresses.  
-  CsmaIpv4Topology::AddIpv4Address (
-      n0, n0ifIndex, Ipv4Address("10.1.1.1"), Ipv4Mask("255.255.255.0"));
-
-  CsmaIpv4Topology::AddIpv4Address (
-      n1, n1ifIndex, Ipv4Address("10.1.1.2"), Ipv4Mask("255.255.255.0"));
+  NS_DEBUG ("nd0 = " << nd0);
+  NS_DEBUG ("nd1 = " << nd1);
+  NS_DEBUG ("nd2 = " << nd2);
+  NS_DEBUG ("nd3 = " << nd3);
+//
+// We've got the "hardware" in place.  Now we need to add IP addresses.
+//
+  NS_DEBUG("Assign IP Addresses.");
+//
+// XXX BUGBUG
+// Need a better way to get the interface index.  The point-to-point topology
+// as implemented can't return the index since it creates interfaces on both
+// sides (i.e., it does AddIpv4Addresses, not AddIpv4Address).  We need a
+// method on Ipv4 to find the interface index corresponding to a given ipv4 
+// address.
+//
+// Assign IP addresses to the net devices and associated interfaces
+// on the lan.  The AddIpv4Address method returns an Ipv4 interface index
+// which we do not need here.
+//
+  CsmaIpv4Topology::AddIpv4Address (n0, nd0, Ipv4Address("10.1.1.1"), 
+    Ipv4Mask("255.255.255.0"));
 
-  CsmaIpv4Topology::AddIpv4Address (
-      n2, n2ifIndex, Ipv4Address("10.1.1.3"), Ipv4Mask("255.255.255.0"));
+  CsmaIpv4Topology::AddIpv4Address (n1, nd1, Ipv4Address("10.1.1.2"), 
+    Ipv4Mask("255.255.255.0"));
+
+  CsmaIpv4Topology::AddIpv4Address (n2, nd2, Ipv4Address("10.1.1.3"), 
+    Ipv4Mask("255.255.255.0"));
   
-  CsmaIpv4Topology::AddIpv4Address (
-      n3, n3ifIndex, Ipv4Address("10.1.1.4"), Ipv4Mask("255.255.255.0"));
-
-  // Create the OnOff application to send UDP datagrams of size
-  // 210 bytes at a rate of 448 Kb/s
-  // from n0 to n1
+  CsmaIpv4Topology::AddIpv4Address (n3, nd3, Ipv4Address("10.1.1.4"), 
+    Ipv4Mask("255.255.255.0"));
+//
+// Create an OnOff application to send UDP datagrams from node zero to node 1.
+//
+  NS_DEBUG("Create Applications.");
   Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
     n0, 
     InetSocketAddress ("10.1.1.2", 80), 
     "Udp",
     ConstantVariable(1), 
     ConstantVariable(0));
-  // Start the application
+//
+// Tell the application when to start and stop.
+//
   ooff->Start(Seconds(1.0));
   ooff->Stop (Seconds(10.0));
-
-  // Create a similar flow from n3 to n0, starting at time 1.1 seconds
+// 
+// Create a similar flow from n3 to n0, starting at time 1.1 seconds
+//
   ooff = Create<OnOffApplication> (
     n3, 
     InetSocketAddress ("10.1.1.1", 80), 
     "Udp",
     ConstantVariable(1), 
     ConstantVariable(0));
-  // Start the application
+
   ooff->Start(Seconds(1.1));
   ooff->Stop (Seconds(10.0));
- 
-  // Configure tracing of all enqueue, dequeue, and NetDevice receive events
-  // Trace output will be sent to the csma-one-subnet.tr file
+//
+// Configure tracing of all enqueue, dequeue, and NetDevice receive events.
+// Trace output will be sent to the file "csma-one-subnet.tr"
+//
+   NS_DEBUG("Configure Tracing.");
   AsciiTrace asciitrace ("csma-one-subnet.tr");
   asciitrace.TraceAllNetDeviceRx ();
   asciitrace.TraceAllQueues ();
-
-  // Also configure some tcpdump traces; each interface will be traced
-  // The output files will be named 
-  // simple-point-to-point.pcap-<nodeId>-<interfaceId>
-  // and can be read by the "tcpdump -r" command (use "-tt" option to
-  // display timestamps correctly)
+//
+// Also configure some tcpdump traces; each interface will be traced.
+// The output files will be named:
+//     csma-one-subnet.pcap-<nodeId>-<interfaceId>
+// and can be read by the "tcpdump -r" command (use "-tt" option to
+// display timestamps correctly)
+//
   PcapTrace pcaptrace ("csma-one-subnet.pcap");
   pcaptrace.TraceAllIp ();
-
+//
+// Now, do the actual simulation.
+//
+  NS_DEBUG("Run Simulation.");
   Simulator::Run ();
-    
   Simulator::Destroy ();
+  NS_DEBUG("Done.");
 }
--- a/examples/mixed-global-routing.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/examples/mixed-global-routing.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -128,13 +128,13 @@
     CsmaTopology::CreateCsmaChannel(
       DataRate(5000000), MilliSeconds(2));
 
-  uint32_t n2ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n2, channelc0,
+  uint32_t n2ifIndex = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, channelc0,
                                          Eui48Address("10:54:23:54:23:50"));
-  uint32_t n3ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n3, channelc0,
+  uint32_t n3ifIndex = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n3, channelc0,
                                          Eui48Address("10:54:23:54:23:51"));
-  uint32_t n4ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n4, channelc0,
+  uint32_t n4ifIndex = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n4, channelc0,
                                          Eui48Address("10:54:23:54:23:52"));
-  uint32_t n5ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n5, channelc0,
+  uint32_t n5ifIndex = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n5, channelc0,
                                          Eui48Address("10:54:23:54:23:53"));
 
   // Later, we add IP addresses.  
--- a/examples/simple-global-routing.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/examples/simple-global-routing.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -157,8 +157,7 @@
   Ptr<PacketSink> sink = Create<PacketSink> (
     n3, 
     InetSocketAddress (Ipv4Address::GetAny (), 80), 
-    "Udp",
-     true);
+    "Udp");
   // Start the sink
   sink->Start (Seconds (1.0));
   sink->Stop (Seconds (10.0));
@@ -178,8 +177,7 @@
   sink = Create<PacketSink> (
     n1, 
     InetSocketAddress (Ipv4Address::GetAny (), 80), 
-    "Udp",
-    true);
+    "Udp");
   // Start the sink
   sink->Start (Seconds (1.1));
   sink->Stop (Seconds (10.0));
--- a/examples/simple-point-to-point.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/examples/simple-point-to-point.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -38,11 +38,7 @@
 // - Tracing of queues and packet receptions to file 
 //   "simple-point-to-point.tr"
 
-#include <iostream>
-#include <fstream>
-#include <string>
-#include <cassert>
-
+#include "ns3/debug.h"
 #include "ns3/command-line.h"
 #include "ns3/default-value.h"
 #include "ns3/ptr.h"
@@ -68,19 +64,34 @@
 
 using namespace ns3;
 
-int main (int argc, char *argv[])
+NS_DEBUG_COMPONENT_DEFINE ("Me");
+
+int 
+main (int argc, char *argv[])
 {
 
   // Users may find it convenient to turn on explicit debugging
   // for selected modules; the below lines suggest how to do this
   // remember to add #include "ns3/debug.h" before enabling these
 #if 0 
+  DebugComponentEnable("Me");
   DebugComponentEnable("Object");
   DebugComponentEnable("Queue");
   DebugComponentEnable("DropTailQueue");
   DebugComponentEnable("Channel");
   DebugComponentEnable("PointToPointChannel");
   DebugComponentEnable("PointToPointNetDevice");
+  DebugComponentEnable("Ipv4L3Protocol");
+  DebugComponentEnable("NetDevice");
+  DebugComponentEnable("PacketSocket");
+  DebugComponentEnable("OnOffApplication");
+  DebugComponentEnable("UdpSocket");
+  DebugComponentEnable("UdpL4Protocol");
+  DebugComponentEnable("Ipv4L3Protocol");
+  DebugComponentEnable("Ipv4StaticRouting");
+  DebugComponentEnable("Ipv4Interface");
+  DebugComponentEnable("ArpIpv4Interface");
+  DebugComponentEnable("Ipv4LoopbackInterface");
 #endif
 
   // Set up some default values for the simulation.  Use the Bind()
@@ -102,12 +113,14 @@
 
   // Here, we will explicitly create four nodes.  In more sophisticated
   // topologies, we could configure a node factory.
+  NS_DEBUG("Create nodes.");
   Ptr<Node> n0 = Create<InternetNode> ();
   Ptr<Node> n1 = Create<InternetNode> (); 
   Ptr<Node> n2 = Create<InternetNode> (); 
   Ptr<Node> n3 = Create<InternetNode> ();
 
   // We create the channels first without any IP addressing information
+  NS_DEBUG("Create channels.");
   Ptr<PointToPointChannel> channel0 = 
     PointToPointTopology::AddPointToPointLink (
       n0, n2, DataRate(5000000), MilliSeconds(2));
@@ -121,6 +134,7 @@
       n2, n3, DataRate(1500000), MilliSeconds(10));
   
   // Later, we add IP addresses.  
+  NS_DEBUG("Assign IP Addresses.");
   PointToPointTopology::AddIpv4Addresses (
       channel0, n0, Ipv4Address("10.1.1.1"),
       n2, Ipv4Address("10.1.1.2"));
@@ -137,13 +151,14 @@
   // NetDevice creation, IP Address assignment, and routing) are 
   // separated because there may be a need to postpone IP Address
   // assignment (emulation) or modify to use dynamic routing
+  NS_DEBUG("Add Static Routes.");
   PointToPointTopology::AddIpv4Routes(n0, n2, channel0);
   PointToPointTopology::AddIpv4Routes(n1, n2, channel1);
   PointToPointTopology::AddIpv4Routes(n2, n3, channel2);
 
-
   // Create the OnOff application to send UDP datagrams of size
   // 210 bytes at a rate of 448 Kb/s
+  NS_DEBUG("Create Applications.");
   Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
     n0, 
     InetSocketAddress ("10.1.3.2", 80), 
@@ -182,10 +197,10 @@
   // Start the sink
   sink->Start (Seconds (1.1));
   sink->Stop (Seconds (10.0));
-  sink->SetQuiet ();  // disable output from the Receive callback
 
   // Here, finish off packet routing configuration
   // This will likely set by some global StaticRouting object in the future
+  NS_DEBUG("Set Default Routes.");
   Ptr<Ipv4> ipv4;
   ipv4 = n0->QueryInterface<Ipv4> (Ipv4::iid);
   ipv4->SetDefaultRoute (Ipv4Address ("10.1.1.2"), 1);
@@ -194,6 +209,7 @@
   
   // Configure tracing of all enqueue, dequeue, and NetDevice receive events
   // Trace output will be sent to the simple-point-to-point.tr file
+  NS_DEBUG("Configure Tracing.");
   AsciiTrace asciitrace ("simple-point-to-point.tr");
   asciitrace.TraceAllQueues ();
   asciitrace.TraceAllNetDeviceRx ();
@@ -206,7 +222,8 @@
   PcapTrace pcaptrace ("simple-point-to-point.pcap");
   pcaptrace.TraceAllIp ();
 
-  Simulator::Run ();
-    
+  NS_DEBUG("Run Simulation.");
+  Simulator::Run ();    
   Simulator::Destroy ();
+  NS_DEBUG("Done.");
 }
--- a/examples/wscript	Tue Sep 11 15:09:55 2007 +0100
+++ b/examples/wscript	Wed Sep 12 18:06:09 2007 +0100
@@ -22,6 +22,10 @@
         ['csma', 'internet-node'])
     obj.source = 'csma-packet-socket.cc'
 
+    obj = bld.create_ns3_program('csma-multicast',
+        ['csma', 'internet-node'])
+    obj.source = 'csma-multicast.cc'
+
     obj = bld.create_ns3_program( 'mixed-global-routing',
         ['point-to-point', 'internet-node', 'global-routing' , 'csma-cd'])
     obj.source = 'mixed-global-routing.cc'
--- a/src/applications/onoff-application.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/applications/onoff-application.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -22,6 +22,7 @@
 // George F. Riley, Georgia Tech, Spring 2007
 // Adapted from ApplicationOnOff in GTNetS.
 
+#include "ns3/debug.h"
 #include "ns3/address.h"
 #include "ns3/node.h"
 #include "ns3/nstime.h"
@@ -34,6 +35,8 @@
 #include "ns3/packet.h"
 #include "onoff-application.h"
 
+NS_DEBUG_COMPONENT_DEFINE ("OnOffApplication");
+
 using namespace std;
 
 namespace ns3 {
@@ -95,30 +98,37 @@
   m_iid = iid;
 }
 
-
 OnOffApplication::~OnOffApplication()
-{}
+{
+  NS_DEBUG("OnOffApplication::~OnOffApplication()");
+}
 
 void 
 OnOffApplication::SetMaxBytes(uint32_t maxBytes)
 {
+  NS_DEBUG("OnOffApplication::SetMaxBytes(" << maxBytes << ")");
   m_maxBytes = maxBytes;
 }
 
 void
 OnOffApplication::SetDefaultRate (const DataRate &rate)
 {
+  NS_DEBUG("OnOffApplication::SetDefaultRate(" << &rate << ")");
   g_defaultRate.SetValue (rate);
 }
+
 void 
 OnOffApplication::SetDefaultSize (uint32_t size)
 {
+  NS_DEBUG("OnOffApplication::SetDefaultSize(" << size << ")");
   g_defaultSize.SetValue (size);
 }
 
 void
 OnOffApplication::DoDispose (void)
 {
+  NS_DEBUG("OnOffApplication::DoDispose()");
+
   m_socket = 0;
   delete m_onTime;
   delete m_offTime;
@@ -130,10 +140,11 @@
   Application::DoDispose ();
 }
 
+// Application Methods
+void OnOffApplication::StartApplication() // Called at time specified by Start
+{
+  NS_DEBUG("OnOffApplication::StartApplication()");
 
-// Application Methods
-void OnOffApplication::StartApplication()    // Called at time specified by Start
-{
   // Create the socket if not already
   if (!m_socket)
     {
@@ -151,8 +162,10 @@
   ScheduleStartEvent();
 }
 
-void OnOffApplication::StopApplication()     // Called at time specified by Stop
+void OnOffApplication::StopApplication() // Called at time specified by Stop
 {
+  NS_DEBUG("OnOffApplication::StopApplication()");
+
   if (m_sendEvent.IsRunning ())
     { // Cancel the pending send packet event
       // Calculate residual bits since last packet sent
@@ -166,23 +179,32 @@
 // Event handlers
 void OnOffApplication::StartSending()
 {
+  NS_DEBUG("OnOffApplication::StartSending ()");
+
   ScheduleNextTx();  // Schedule the send packet event
 }
 
 void OnOffApplication::StopSending()
 {
+  NS_DEBUG("OnOffApplication::StopSending ()");
+
   Simulator::Cancel(m_sendEvent);
 }
 
 // Private helpers
 void OnOffApplication::ScheduleNextTx()
 {
+  NS_DEBUG("OnOffApplication::ScheduleNextTx ()");
+
   if (m_totBytes < m_maxBytes)
     {
       uint32_t bits = m_pktSize * 8 - m_residualBits;
+      NS_DEBUG("OnOffApplication::ScheduleNextTx (): bits = " << bits);
       Time nextTime(Seconds (bits / 
         static_cast<double>(m_cbrRate.GetBitRate()))); // Time till next packet
-      m_sendEvent = Simulator::Schedule(nextTime, &OnOffApplication::SendPacket, this);
+      NS_DEBUG("OnOffApplication::ScheduleNextTx (): nextTime = " << nextTime);
+      m_sendEvent = Simulator::Schedule(nextTime, 
+                                        &OnOffApplication::SendPacket, this);
     }
   else
     { // All done, cancel any pending events
@@ -192,12 +214,18 @@
 
 void OnOffApplication::ScheduleStartEvent()
 {  // Schedules the event to start sending data (switch to the "On" state)
+  NS_DEBUG("OnOffApplication::ScheduleStartEvent ()");
+
   Time offInterval = Seconds(m_offTime->GetValue());
+  NS_DEBUG("OnOffApplication::ScheduleStartEvent (): "
+    "start at " << offInterval);
   m_startStopEvent = Simulator::Schedule(offInterval, &OnOffApplication::StartSending, this);
 }
 
 void OnOffApplication::ScheduleStopEvent()
 {  // Schedules the event to stop sending data (switch to "Off" state)
+  NS_DEBUG("OnOffApplication::ScheduleStopEvent ()");
+
   Time onInterval = Seconds(m_onTime->GetValue());
   Simulator::Schedule(onInterval, &OnOffApplication::StopSending, this);
 }
@@ -205,6 +233,8 @@
   
 void OnOffApplication::SendPacket()
 {
+  NS_DEBUG("OnOffApplication::SendPacket ()");
+
   NS_ASSERT (m_sendEvent.IsExpired ());
   m_socket->Send(Packet (m_pktSize));
   m_totBytes += m_pktSize;
@@ -215,6 +245,8 @@
 
 void OnOffApplication::ConnectionSucceeded(Ptr<Socket>)
 {
+  NS_DEBUG("OnOffApplication::ConnectionSucceeded ()");
+
   m_connected = true;
   ScheduleStartEvent();
 }
--- a/src/applications/packet-sink.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/applications/packet-sink.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -1,20 +1,22 @@
-/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
-//
-// Copyright (c) 2006 Georgia Tech Research Corporation
-//
-// 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
-//
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright 2007 University of Washington
+ * 
+ * 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:  Tom Henderson (tomhend@u.washington.edu)
+ */
 #include "ns3/address.h"
 #include "ns3/debug.h"
 #include "ns3/inet-socket-address.h"
@@ -35,35 +37,26 @@
 
 PacketSink::PacketSink (Ptr<Node> n, 
                         const Address &local,
-                        std::string iid,
-                        bool quiet)
+                        std::string iid)
   :  Application(n)
 {
-  Construct (n, local, iid, quiet);
+  Construct (n, local, iid);
 }
 
 void
 PacketSink::Construct (Ptr<Node> n, 
                        const Address &local,
-                       std::string iid,
-                       bool quiet)
+                       std::string iid)
 {
   m_socket = 0;
   m_local = local;
   m_iid = iid;
-  m_quiet = quiet;
 }
 
 PacketSink::~PacketSink()
 {}
 
 void
-PacketSink::SetQuiet()
-{
-  m_quiet = true;
-}
-
-void
 PacketSink::DoDispose (void)
 {
   m_socket = 0;
@@ -99,19 +92,17 @@
     }
 }
 
-// This callback body suggested by Joe Kopena's wiki
+// This LOG output inspired by the application on Joseph Kopena's wiki
 void PacketSink::Receive(Ptr<Socket> socket, const Packet &packet,
                        const Address &from) 
 {
-  if (!m_quiet)
+  if (InetSocketAddress::IsMatchingType (from))
     {
-      if (InetSocketAddress::IsMatchingType (from))
-        {
-          InetSocketAddress address = InetSocketAddress::ConvertFrom (from);
-          NS_DEBUG ( __PRETTY_FUNCTION__ << ": Received " << 
-            packet.GetSize() << " bytes from " << address.GetIpv4() << " [" 
-            << address << "]---'" << packet.PeekData() << "'");
-        }
+      InetSocketAddress address = InetSocketAddress::ConvertFrom (from);
+      NS_DEBUG ( __PRETTY_FUNCTION__ << ": Received " << 
+        packet.GetSize() << " bytes from " << address.GetIpv4() << " [" 
+        << address << "]---'" << packet.PeekData() << "'");
+      // TODO:  Add a tracing source here
     }
 }
 
--- a/src/applications/packet-sink.h	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/applications/packet-sink.h	Wed Sep 12 18:06:09 2007 +0100
@@ -1,21 +1,22 @@
-/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
-//
-// Copyright (c) 2006 Georgia Tech Research Corporation
-//
-// 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
-//
-//
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright 2007 University of Washington
+ * 
+ * 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:  Tom Henderson (tomhend@u.washington.edu)
+ */
 
 #ifndef __packet_sink_h__
 #define __packet_sink_h__
@@ -33,34 +34,34 @@
 /**
  * \brief Receive and consume traffic generated to an IP address and port
  *
- * This Application can be used as a receiver for packets generated by
- * traffic sourcing applications such as OnOffApplication.  The constructor
- * specifies the Address (IP address and port) and the transport protocol
- * to use.   A virtual Receive () method is installed as a callback on 
- * the receiving socket.  By default, it prints out the size of packets
- * and their address.
+ * This application was written to complement OnOffApplication, but it
+ * is more general so a PacketSink name was selected.  Functionally it is
+ * important to use in multicast situations, so that reception of the layer-2
+ * multicast frames of interest are enabled, but it is also useful for
+ * unicast as an example of how you can write something simple to receive
+ * packets at the application layer.  Also, if an IP stack generates 
+ * ICMP Port Unreachable errors, receiving applications will be needed.
+ *
+ * The constructor specifies the Address (IP address and port) and the 
+ * transport protocol to use.   A virtual Receive () method is installed 
+ * as a callback on the receiving socket.  By default, when logging is
+ * enabled, it prints out the size of packets and their address, but
+ * we intend to also add a tracing source to Receive() at a later date.
  */
 class PacketSink : public Application 
 {
 public:
   /**
    * \param n node associated to this application
-   * \param local local ip address
-   * \param iid
-   * \param ontime on time random variable
-   * \param offtime off time random variable
+   * \param local local address to bind to
+   * \param iid string to identify transport protocol of interest
    */
   PacketSink (Ptr<Node> n,
               const Address &local,
-              std::string iid, bool quiet=false);
+              std::string iid);
 
   virtual ~PacketSink ();
 
-  /**
-   * \brief Turn off the logging output for the receive callback
-   */
-  void SetQuiet (void);
-
 protected:
   virtual void DoDispose (void);
 private:
@@ -70,15 +71,13 @@
 
   void Construct (Ptr<Node> n,
                   const Address &local,
-                  std::string iid,
-                  bool quiet);
+                  std::string iid);
 
   virtual void Receive (Ptr<Socket> socket, const Packet& packet, const Address& from);
 
   Ptr<Socket>     m_socket;       // Associated socket
   Address         m_local;        // Local address to bind to
   std::string     m_iid;          // Protocol name (e.g., "Udp")
-  bool            m_quiet;        // Governs whether receive callback is quiet 
   
 };
 
--- a/src/common/buffer.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/common/buffer.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -1,7 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2005,2006 INRIA
- * All rights reserved.
+ * Copyright (c) 2005,2006,2007 INRIA
  *
  * 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
@@ -20,385 +19,534 @@
  */
 #include "buffer.h"
 #include "ns3/assert.h"
-
+#include "ns3/debug.h"
 #include <iostream>
-//#define TRACE(x) std::cout << x << std::endl;
-#define TRACE(x)
+
+NS_DEBUG_COMPONENT_DEFINE ("Buffer");
+
+#define DEBUG_INTERNAL_STATE(y)                                                                    \
+NS_DEBUG (y << "start="<<m_start<<", end="<<m_end<<", zero start="<<m_zeroAreaStart<<              \
+          ", zero end="<<m_zeroAreaEnd<<", count="<<m_data->m_count<<", size="<<m_data->m_size<<   \
+          ", dirty start="<<m_data->m_dirtyStart<<", dirty end="<<m_data->m_dirtyEnd)
+
+#ifdef BUFFER_HEURISTICS
+#define HEURISTICS(x) x
+#else
+#define HEURISTICS(x)
+#endif
+
+//#define PRINT_STATS 1
 
 namespace ns3 {
 
-Buffer::BufferDataList  Buffer::m_freeList;
-uint32_t Buffer::m_maxTotalAddStart = 0;
-uint32_t Buffer::m_maxTotalAddEnd = 0;
+/**
+ * This data structure is variable-sized through its last member whose size
+ * is determined at allocation time and stored in the m_size field.
+ *
+ * The so-called "dirty area" describes the area in the buffer which
+ * has been reserved and used by a user. Multiple Buffer instances
+ * may reference the same BufferData object instance and may
+ * reference different parts of the underlying byte buffer. The
+ * "dirty area" is union of all the areas referenced by the Buffer
+ * instances which reference the same BufferData instance.
+ * New user data can be safely written only outside of the "dirty
+ * area" if the reference count is higher than 1 (that is, if
+ * more than one Buffer instance references the same BufferData).
+ */
+struct BufferData {
+  /* The reference count of an instance of this data structure.
+   * Each buffer which references an instance holds a count.
+   */
+  uint32_t m_count;
+  /* the size of the m_data field below.
+   */
+  uint32_t m_size;
+  /* offset from the start of the m_data field below to the
+   * start of the area in which user bytes were written.
+   */
+  uint32_t m_dirtyStart;
+  /* offset from the start of the m_data field below to the
+   * end of the area in which user bytes were written.
+   */
+  uint32_t m_dirtyEnd;
+  /* The real data buffer holds _at least_ one byte.
+   * Its real size is stored in the m_size field.
+   */
+  uint8_t m_data[1];
+};
+class BufferDataList : public std::vector<struct BufferData*>
+{
+public:
+  ~BufferDataList ();
+};
 
-Buffer::BufferDataList::~BufferDataList ()
+static struct BufferData *BufferAllocate (uint32_t reqSize);
+
+static void BufferDeallocate (struct BufferData *data);
+
+
+} // namespace ns3
+
+namespace ns3 {
+
+#ifdef BUFFER_HEURISTICS
+static uint32_t g_recommendedStart = 0;
+static uint64_t g_nAddNoRealloc = 0;
+static uint64_t g_nAddRealloc = 0;
+static BufferDataList  g_freeList;
+static uint32_t g_maxSize = 0;
+static uint64_t g_nAllocs = 0;
+static uint64_t g_nCreates = 0;
+#endif /* BUFFER_HEURISTICS */
+
+BufferDataList::~BufferDataList ()
 {
+#ifdef PRINT_STATS
+#ifdef BUFFER_HEURISTICS
+  double efficiency;
+  efficiency = g_nAllocs;
+  efficiency /= g_nCreates;
+  std::cout <<"buffer free list efficiency="<<efficiency<<" (lower is better)" << std::endl;
+  std::cout <<"buffer free list max size="<<g_maxSize<<std::endl;
+  std::cout <<"buffer free list recommended start="<<g_recommendedStart<<std::endl;
+  double addEfficiency;
+  addEfficiency = g_nAddRealloc;
+  addEfficiency /= g_nAddNoRealloc;
+  std::cout <<"buffer add efficiency=" << addEfficiency << " (lower is better)"<<std::endl;
+  //std::cout <<"n add reallocs="<< g_nAddRealloc << std::endl;
+  //std::cout <<"n add no reallocs="<< g_nAddNoRealloc << std::endl;
+#endif /* BUFFER_HEURISTICS */
+#endif /* PRINT_STATS */
   for (BufferDataList::iterator i = begin ();
        i != end (); i++)
     {
-      Buffer::Deallocate (*i);
+      BufferDeallocate (*i);
     }
 }
 
-struct Buffer::BufferData *
-Buffer::Allocate (uint32_t reqSize, uint32_t reqStart)
+struct BufferData *
+BufferAllocate (uint32_t reqSize)
 {
   if (reqSize == 0) 
     {
       reqSize = 1;
     }
   NS_ASSERT (reqSize >= 1);
-  uint32_t size = reqSize - 1 + sizeof (struct Buffer::BufferData);
+  uint32_t size = reqSize - 1 + sizeof (struct BufferData);
   uint8_t *b = new uint8_t [size];
-  struct BufferData *data = reinterpret_cast<struct Buffer::BufferData*>(b);
+  struct BufferData *data = reinterpret_cast<struct BufferData*>(b);
   data->m_size = reqSize;
-  data->m_initialStart = reqStart;
-  data->m_dirtyStart = reqStart;
-  data->m_dirtySize = 0;
   data->m_count = 1;
   return data;
 }
 
 void
-Buffer::Deallocate (struct Buffer::BufferData *data)
+BufferDeallocate (struct BufferData *data)
 {
+  NS_ASSERT (data->m_count == 0);
   uint8_t *buf = reinterpret_cast<uint8_t *> (data);
   delete [] buf;
 }
-#ifdef USE_FREE_LIST
+#ifdef BUFFER_HEURISTICS
 void
-Buffer::Recycle (struct Buffer::BufferData *data)
+Buffer::Recycle (struct BufferData *data)
 {
   NS_ASSERT (data->m_count == 0);
-  /* get rid of it if it is too small for later reuse. */
-  if (data->m_size < (Buffer::m_maxTotalAddStart + Buffer::m_maxTotalAddEnd)) 
-    {
-      Buffer::Deallocate (data);
-      return; 
-    }
+  g_maxSize = std::max (g_maxSize, data->m_size);
   /* feed into free list */
-  if (Buffer::m_freeList.size () > 1000) 
+  if (data->m_size < g_maxSize ||
+      g_freeList.size () > 1000)
     {
-      Buffer::Deallocate (data);
-    } 
-  else 
+      BufferDeallocate (data);
+    }
+  else
     {
-      Buffer::m_freeList.push_back (data);
+      g_freeList.push_back (data);
     }
 }
 
-Buffer::BufferData *
-Buffer::Create (void)
+BufferData *
+Buffer::Create (uint32_t dataSize)
 {
   /* try to find a buffer correctly sized. */
-  while (!Buffer::m_freeList.empty ()) 
+  g_nCreates++;
+  while (!g_freeList.empty ()) 
     {
-      struct Buffer::BufferData *data = Buffer::m_freeList.back ();
-      Buffer::m_freeList.pop_back ();
-      if (data->m_size >= (m_maxTotalAddStart + m_maxTotalAddEnd)) 
+      struct BufferData *data = g_freeList.back ();
+      g_freeList.pop_back ();
+      if (data->m_size >= dataSize) 
         {
-          data->m_initialStart = m_maxTotalAddStart;
-          data->m_dirtyStart = m_maxTotalAddStart;
-          data->m_dirtySize = 0;
           data->m_count = 1;
           return data;
         }
-      Buffer::Deallocate (data);
+      BufferDeallocate (data);
     }
-  struct Buffer::BufferData *data = Buffer::Allocate (m_maxTotalAddStart+m_maxTotalAddEnd,
-                              m_maxTotalAddStart);
+  g_nAllocs++;
+  struct BufferData *data = BufferAllocate (dataSize);
   NS_ASSERT (data->m_count == 1);
   return data;
 }
 #else
 void
-Buffer::Recycle (struct Buffer::BufferData *data)
+Buffer::Recycle (struct BufferData *data)
 {
-  Buffer::Deallocate (data);
+  NS_ASSERT (data->m_count == 0);
+  BufferDeallocate (data);
 }
 
-Buffer::BufferData *
-Buffer::Create (void)
+BufferData *
+Buffer::Create (uint32_t size)
 {
-  return Buffer::Allocate (m_maxTotalAddStart+m_maxTotalAddEnd,
-                           m_maxTotalAddStart);
+  return BufferAllocate (size);
 }
 #endif
 
-}; // namespace ns3
+Buffer::Buffer ()
+{
+  Initialize (0);
+}
 
+Buffer::Buffer (uint32_t dataSize)
+{
+  Initialize (dataSize);
+}
 
-#include "ns3/assert.h"
+bool
+Buffer::CheckInternalState (void) const
+{
+  bool offsetsOk = 
+    m_start <= m_zeroAreaStart &&
+    m_zeroAreaStart <= m_zeroAreaEnd &&
+    m_zeroAreaEnd <= m_end;
+  bool dirtyOk =
+    m_start >= m_data->m_dirtyStart &&
+    m_end <= m_data->m_dirtyEnd;
+  bool internalSizeOk = m_end - (m_zeroAreaEnd - m_zeroAreaStart) <= m_data->m_size &&
+    m_start <= m_data->m_size &&
+    m_zeroAreaStart <= m_data->m_size;
 
-namespace ns3 {
+  NS_ASSERT (offsetsOk);
+  NS_ASSERT (dirtyOk);
+  NS_ASSERT (internalSizeOk);
 
+  return m_data->m_count > 0 && offsetsOk && dirtyOk && 
+    internalSizeOk;
+}
 
-void 
-Buffer::AddAtStart (uint32_t start)
+void
+Buffer::Initialize (uint32_t zeroSize)
 {
-  NS_ASSERT (m_start <= m_data->m_initialStart);
-  bool isDirty = m_data->m_count > 1 && m_start > m_data->m_dirtyStart;
-  if (m_start >= start && !isDirty) 
-    {
-      /* enough space in the buffer and not dirty. */
-      m_start -= start;
-      m_size += start;
-    } 
-  else if (m_size + start <= m_data->m_size && !isDirty) 
+  m_data = Buffer::Create (0);
+#ifdef BUFFER_HEURISTICS
+  m_start = std::min (m_data->m_size, g_recommendedStart);
+  m_maxZeroAreaStart = m_start;
+#else
+  m_start = 0;
+#endif /* BUFFER_HEURISTICS */
+  m_zeroAreaStart = m_start;
+  m_zeroAreaEnd = m_zeroAreaStart + zeroSize;
+  m_end = m_zeroAreaEnd;
+  m_data->m_dirtyStart = m_start;
+  m_data->m_dirtyEnd = m_end;
+  NS_ASSERT (CheckInternalState ());
+}
+
+Buffer::Buffer (Buffer const&o)
+  : m_data (o.m_data),
+#ifdef BUFFER_HEURISTICS
+    m_maxZeroAreaStart (o.m_zeroAreaStart),
+#endif
+    m_zeroAreaStart (o.m_zeroAreaStart),
+    m_zeroAreaEnd (o.m_zeroAreaEnd),
+    m_start (o.m_start),
+    m_end (o.m_end)
+{
+  m_data->m_count++;
+  NS_ASSERT (CheckInternalState ());
+}
+
+Buffer &
+Buffer::operator = (Buffer const&o)
+{
+  NS_ASSERT (CheckInternalState ());
+  if (m_data != o.m_data) 
     {
-      /* enough space but need to move data around to fit new data */
-      memmove (m_data->m_data + start, GetStart (), m_size);
-      NS_ASSERT (start > m_start);
-      m_data->m_initialStart += start - m_start;
-      m_start = 0;
-      m_size += start;
-    } 
-  else if (m_start < start) 
-    {
-      /* not enough space in buffer */
-      uint32_t newSize = m_size + start;
-      struct Buffer::BufferData *newData = Buffer::Allocate (newSize, 0);
-      memcpy (newData->m_data + start, GetStart (), m_size);
-      newData->m_initialStart = m_data->m_initialStart + start;
-      m_data->m_count--;
-      if (m_data->m_count == 0) 
-        {
-          Buffer::Deallocate (m_data);
-        }
-      m_data = newData;
-      m_start = 0;
-      m_size = newSize;
-    } 
-  else 
-    {
-      /* enough space in the buffer but it is dirty ! */
-      NS_ASSERT (isDirty);
-      struct Buffer::BufferData *newData = Buffer::Create ();
-      memcpy (newData->m_data + m_start, GetStart (), m_size);
-      newData->m_initialStart = m_data->m_initialStart;
+      // not assignment to self.
       m_data->m_count--;
       if (m_data->m_count == 0) 
         {
           Recycle (m_data);
         }
-      m_data = newData;
+      m_data = o.m_data;
+      m_data->m_count++;
+    }
+  HEURISTICS (
+  g_recommendedStart = std::max (g_recommendedStart, m_maxZeroAreaStart);
+  m_maxZeroAreaStart = o.m_maxZeroAreaStart;
+  );
+  m_zeroAreaStart = o.m_zeroAreaStart;
+  m_zeroAreaEnd = o.m_zeroAreaEnd;
+  m_start = o.m_start;
+  m_end = o.m_end;
+  NS_ASSERT (CheckInternalState ());
+  return *this;
+}
+
+Buffer::~Buffer ()
+{
+  HEURISTICS (g_recommendedStart = std::max (g_recommendedStart, m_maxZeroAreaStart));
+  m_data->m_count--;
+  if (m_data->m_count == 0) 
+    {
+      Recycle (m_data);
+    }
+}
+
+uint32_t 
+Buffer::GetSize (void) const
+{
+  NS_ASSERT (CheckInternalState ());
+  return m_end - m_start;
+}
+
+Buffer::Iterator 
+Buffer::Begin (void) const
+{
+  NS_ASSERT (CheckInternalState ());
+  return Buffer::Iterator (this);
+}
+Buffer::Iterator 
+Buffer::End (void) const
+{
+  NS_ASSERT (CheckInternalState ());
+  return Buffer::Iterator (this, false);
+}
+
+uint32_t
+Buffer::GetInternalSize (void) const
+{
+  return m_zeroAreaStart - m_start + m_end - m_zeroAreaEnd;
+}
+uint32_t
+Buffer::GetInternalEnd (void) const
+{
+  return m_end - (m_zeroAreaEnd - m_zeroAreaStart);
+}
+
+void 
+Buffer::AddAtStart (uint32_t start)
+{
+  NS_ASSERT (CheckInternalState ());
+  bool isDirty = m_data->m_count > 1 && m_start > m_data->m_dirtyStart;
+  if (m_start >= start && !isDirty)
+    {
+      /* enough space in the buffer and not dirty. 
+       * To add: |..|
+       * Before: |*****---------***|
+       * After:  |***..---------***|
+       */
+      NS_ASSERT (m_data->m_count == 1 || m_start == m_data->m_dirtyStart);
       m_start -= start;
-      m_size += start;
+      HEURISTICS (g_nAddNoRealloc++);
     } 
+#if 0
+  // the following is an optimization
+  else if (m_start >= start)
+    {
+      struct BufferData *newData = Buffer::Create (m_data->m_size);
+      memcpy (newData->m_data + m_start, m_data->m_data + m_start, GetInternalSize ());
+      m_data->m_count--;
+      if (m_data->m_count == 0)
+        {
+          Buffer::Recycle (m_data);
+        }
+      m_data = newData;
+
+      m_start -= start;
+      HEURISTICS (g_nAddRealloc++);
+    }
+  else
+    {
+      NS_ASSERT (m_start < start);
+#else
+  else
+    {
+#endif
+      uint32_t newSize = GetInternalSize () + start;
+      struct BufferData *newData = Buffer::Create (newSize);
+      memcpy (newData->m_data + start, m_data->m_data + m_start, GetInternalSize ());
+      m_data->m_count--;
+      if (m_data->m_count == 0)
+        {
+          Buffer::Recycle (m_data);
+        }
+      m_data = newData;
+
+      int32_t delta = start - m_start;
+      m_start = 0;
+      m_zeroAreaStart += delta;
+      m_zeroAreaEnd += delta;
+      m_end += delta;
+
+      HEURISTICS (g_nAddRealloc++);
+    }
+  HEURISTICS (m_maxZeroAreaStart = std::max (m_maxZeroAreaStart, m_zeroAreaStart));
   // update dirty area
   m_data->m_dirtyStart = m_start;
-  m_data->m_dirtySize = m_size;
-  // update m_maxTotalAddStart
-  uint32_t addedAtStart;
-  if (m_data->m_initialStart > m_start) 
-    {
-      addedAtStart = m_data->m_initialStart - m_start;
-    } 
-  else 
-    {
-      addedAtStart = 0;
-    }
-  if (addedAtStart > m_maxTotalAddStart) 
-    {
-      m_maxTotalAddStart = addedAtStart;
-    }
-  TRACE ("start add="<<start<<", start="<<m_start<<", size="<<m_size<<", zero="<<m_zeroAreaSize<<
-         ", real size="<<m_data->m_size<<", ini start="<<m_data->m_initialStart<<
-         ", dirty start="<<m_data->m_dirtyStart<<", dirty size="<<m_data->m_dirtySize); 
+  m_data->m_dirtyEnd = m_end;
+  DEBUG_INTERNAL_STATE ("add start=" << start << ", ");
+  NS_ASSERT (CheckInternalState ());
 }
 void 
 Buffer::AddAtEnd (uint32_t end)
 {
-  NS_ASSERT (m_start <= m_data->m_initialStart);
-  bool isDirty = m_data->m_count > 1 &&
-      m_start + m_size < m_data->m_dirtyStart + m_data->m_dirtySize;
-  if (m_start + m_size + end <= m_data->m_size && !isDirty) 
-    {
-      /* enough space in buffer and not dirty */
-      m_size += end;
-    } 
-  else if (m_size + end <= m_data->m_size && !isDirty) 
+  NS_ASSERT (CheckInternalState ());
+  bool isDirty = m_data->m_count > 1 && m_end < m_data->m_dirtyEnd;
+  if (GetInternalEnd () + end <= m_data->m_size && !isDirty)
     {
-      /* enough space but need to move data around to fit the extra data */
-      uint32_t newStart = m_data->m_size - (m_size + end);
-      memmove (m_data->m_data + newStart, GetStart (), m_size);
-      NS_ASSERT (newStart < m_start);
-      m_data->m_initialStart -= m_start - newStart;
-      m_start = newStart;
-      m_size += end;
+      /* enough space in buffer and not dirty
+       * Add:    |...|
+       * Before: |**----*****|
+       * After:  |**----...**|
+       */
+      NS_ASSERT (m_data->m_count == 1 || m_end == m_data->m_dirtyEnd);
+      m_end += end;
+
+      HEURISTICS (g_nAddNoRealloc++);
     } 
-  else if (m_start + m_size + end > m_data->m_size) 
+#if 0
+  // this is an optimization
+  else if (GetInternalEnd () + end > m_data->m_size)
     {
-      /* not enough space in buffer */
-      uint32_t newSize = m_size + end;
-      struct Buffer::BufferData *newData = Buffer::Allocate (newSize, 0);
-      memcpy (newData->m_data, GetStart (), m_size);
-      newData->m_initialStart = m_data->m_initialStart - m_start;
+      struct BufferData *newData = Buffer::Create (newSize);
+      memcpy (newData->m_data + m_start, m_data->m_data + m_start, GetInternalSize ());
       m_data->m_count--;
       if (m_data->m_count == 0) 
         {
-          Buffer::Deallocate (m_data);
+          Buffer::Recycle (m_data);
         }
       m_data = newData;
-      m_size = newSize;
-      m_start = 0;
-    } 
-  else 
+
+      m_end += end;
+      HEURISTICS (g_nAddRealloc++);
+    }
+#endif
+  else
     {
-      /* enough space in the buffer but it is dirty ! */
-      NS_ASSERT (isDirty);
-      struct Buffer::BufferData *newData = Buffer::Create ();
-      memcpy (newData->m_data + m_start, GetStart (), m_size);
-      newData->m_initialStart = m_data->m_initialStart;
+      uint32_t newSize = GetInternalSize () + end;
+      struct BufferData *newData = Buffer::Create (newSize);
+      memcpy (newData->m_data, m_data->m_data + m_start, GetInternalSize ());
       m_data->m_count--;
       if (m_data->m_count == 0) 
         {
-          Recycle (m_data);
+          Buffer::Recycle (m_data);
         }
       m_data = newData;
-      m_size += end;
+
+
+      m_zeroAreaStart -= m_start;
+      m_zeroAreaEnd -= m_start;
+      m_end -= m_start;
+      m_start = 0;
+
+      m_end += end;
+
+      HEURISTICS (g_nAddRealloc++);
     } 
+  HEURISTICS (m_maxZeroAreaStart = std::max (m_maxZeroAreaStart, m_zeroAreaStart));
   // update dirty area
   m_data->m_dirtyStart = m_start;
-  m_data->m_dirtySize = m_size;
-  // update m_maxTotalAddEnd
-  uint32_t endLoc = m_start + m_size;
-  uint32_t addedAtEnd;
-  if (m_data->m_initialStart < endLoc) 
-    {
-      addedAtEnd = endLoc - m_data->m_initialStart;
-    } 
-  else 
-    {
-      addedAtEnd = 0;
-    }
-  if (addedAtEnd > m_maxTotalAddEnd) 
-    {
-      m_maxTotalAddEnd = addedAtEnd;
-    }
-  TRACE ("end add="<<end<<", start="<<m_start<<", size="<<m_size<<", zero="<<m_zeroAreaSize<<
-         ", real size="<<m_data->m_size<<", ini start="<<m_data->m_initialStart<<
-         ", dirty start="<<m_data->m_dirtyStart<<", dirty size="<<m_data->m_dirtySize); 
+  m_data->m_dirtyEnd = m_end;
+  DEBUG_INTERNAL_STATE ("add end=" << end << ", ");
+  NS_ASSERT (CheckInternalState ());
 }
 
 void 
 Buffer::RemoveAtStart (uint32_t start)
 {
-  if (m_zeroAreaSize == 0) 
+  NS_ASSERT (CheckInternalState ());
+  uint32_t newStart = m_start + start;
+  if (newStart <= m_zeroAreaStart)
+    {
+      /* only remove start of buffer 
+       */
+      m_start = newStart;
+    }
+  else if (newStart <= m_zeroAreaEnd)
     {
-      if (m_size <= start) 
-        {
-          m_start += m_size;
-          m_size = 0;
-        } 
-      else 
-        {
-          m_start += start;
-          m_size -= start;
-        }
+      /* remove start of buffer _and_ start of zero area
+       */
+      uint32_t delta = newStart - m_zeroAreaStart;
+      m_start = m_zeroAreaStart;
+      m_zeroAreaEnd -= delta;
+      m_end -= delta;
     } 
+  else if (newStart <= m_end)
+    {
+      /* remove start of buffer, complete zero area, and part
+       * of end of buffer 
+       */
+      NS_ASSERT (m_end >= start);
+      uint32_t zeroSize = m_zeroAreaEnd - m_zeroAreaStart;
+      m_start = newStart - zeroSize;
+      m_end -= zeroSize;
+      m_zeroAreaStart = m_start;
+      m_zeroAreaEnd = m_start;
+    }
   else 
     {
-      NS_ASSERT (m_data->m_initialStart >= m_start);
-      uint32_t zeroStart = m_data->m_initialStart - m_start;
-      uint32_t zeroEnd = zeroStart + m_zeroAreaSize;
-      uint32_t dataEnd = m_size + m_zeroAreaSize;
-      if (start <= zeroStart) 
-        {
-          /* only remove start of buffer */
-          m_start += start;
-          m_size -= start;
-        } 
-      else if (start <= zeroEnd) 
-        {
-          /* remove start of buffer _and_ start of zero area */
-          m_start += zeroStart;
-          uint32_t zeroDelta = start - zeroStart;
-          m_zeroAreaSize -= zeroDelta;
-          NS_ASSERT (zeroDelta <= start);
-          m_size -= zeroStart;
-        } 
-      else if (start <= dataEnd) 
-        {
-          /* remove start of buffer, complete zero area, and part
-           * of end of buffer */
-          m_start += start - m_zeroAreaSize;
-          m_size -= start - m_zeroAreaSize;
-          m_zeroAreaSize = 0;
-        } 
-      else 
-        {
-          /* remove all buffer */
-          m_start += m_size;
-          m_size = 0;
-          m_zeroAreaSize = 0;
-        }
+      /* remove all buffer */
+      m_end -= m_zeroAreaEnd - m_zeroAreaStart;
+      m_start = m_end;
+      m_zeroAreaEnd = m_end;
+      m_zeroAreaStart = m_end;
     }
-  TRACE ("start remove="<<start<<", start="<<m_start<<", size="<<m_size<<
-         ", zero="<<m_zeroAreaSize<<
-         ", real size="<<m_data->m_size<<", ini start="<<m_data->m_initialStart<<
-         ", dirty start="<<m_data->m_dirtyStart<<", dirty size="<<m_data->m_dirtySize); 
+  HEURISTICS (m_maxZeroAreaStart = std::max (m_maxZeroAreaStart, m_zeroAreaStart));
+  DEBUG_INTERNAL_STATE ("rem start=" << start << ", ");
+  NS_ASSERT (CheckInternalState ());
 }
 void 
 Buffer::RemoveAtEnd (uint32_t end)
 {
-  if (m_zeroAreaSize == 0) 
+  NS_ASSERT (CheckInternalState ());
+  uint32_t newEnd = m_end - std::min (end, m_end - m_start);
+  if (newEnd > m_zeroAreaEnd)
     {
-      if (m_size <= end) 
-        {
-          m_size = 0;
-        } 
-      else 
-        {
-          m_size -= end;
-        } 
-    } 
-  else 
+      /* remove part of end of buffer */
+      m_end = newEnd;
+    }
+  else if (newEnd > m_zeroAreaStart)
+    {
+      /* remove end of buffer, part of zero area */
+      m_end = newEnd;
+      m_zeroAreaEnd = newEnd;
+    }
+  else if (newEnd > m_start)
     {
-      NS_ASSERT (m_data->m_initialStart >= m_start);
-      uint32_t zeroStart = m_data->m_initialStart - m_start;
-      uint32_t zeroEnd = zeroStart + m_zeroAreaSize;
-      uint32_t dataEnd = m_size + m_zeroAreaSize;
-      NS_ASSERT (zeroStart <= m_size);
-      NS_ASSERT (zeroEnd <= m_size + m_zeroAreaSize);
-      if (dataEnd <= end) 
-        {
-          /* remove all buffer */
-          m_zeroAreaSize = 0;
-          m_start += m_size;
-          m_size = 0;
-        } 
-      else if (dataEnd - zeroStart <= end) 
-        {
-          /* remove end of buffer, zero area, part of start of buffer */
-          NS_ASSERT (end >= m_zeroAreaSize);
-          m_size -= end - m_zeroAreaSize;
-          m_zeroAreaSize = 0;
-        } 
-      else if (dataEnd - zeroEnd <= end) 
-        {
-          /* remove end of buffer, part of zero area */
-          uint32_t zeroDelta = end - (dataEnd - zeroEnd);
-          m_zeroAreaSize -= zeroDelta;
-          m_size -= end - zeroDelta;
-        } 
-      else 
-        {
-          /* remove part of end of buffer */
-          m_size -= end;
-        }
+      /* remove end of buffer, zero area, part of start of buffer */
+      m_end = newEnd;
+      m_zeroAreaEnd = newEnd;
+      m_zeroAreaStart = newEnd;
     }
-  TRACE ("end remove="<<end<<", start="<<m_start<<", size="<<m_size<<", zero="<<m_zeroAreaSize<<
-         ", real size="<<m_data->m_size<<", ini start="<<m_data->m_initialStart<<
-         ", dirty start="<<m_data->m_dirtyStart<<", dirty size="<<m_data->m_dirtySize); 
+  else
+    {
+      /* remove all buffer */
+      m_end = m_start;
+      m_zeroAreaEnd = m_start;
+      m_zeroAreaStart = m_start;
+    }
+  HEURISTICS (m_maxZeroAreaStart = std::max (m_maxZeroAreaStart, m_zeroAreaStart));
+  DEBUG_INTERNAL_STATE ("rem end=" << end << ", ");
+  NS_ASSERT (CheckInternalState ());
 }
 
 Buffer 
 Buffer::CreateFragment (uint32_t start, uint32_t length) const
 {
-  uint32_t zeroStart = m_data->m_initialStart - m_start;
-  uint32_t zeroEnd = zeroStart + m_zeroAreaSize;
-  if (m_zeroAreaSize != 0 &&
+  NS_ASSERT (CheckInternalState ());
+  uint32_t zeroStart = m_zeroAreaStart - m_start;
+  uint32_t zeroEnd = zeroStart + m_zeroAreaEnd;
+  if (m_zeroAreaEnd != 0 &&
       start + length > zeroStart &&
       start <= zeroEnd) 
     {
@@ -407,51 +555,433 @@
   Buffer tmp = *this;
   tmp.RemoveAtStart (start);
   tmp.RemoveAtEnd (GetSize () - (start + length));
+  NS_ASSERT (CheckInternalState ());
   return tmp;
 }
 
 Buffer 
 Buffer::CreateFullCopy (void) const
 {
-  if (m_zeroAreaSize != 0) 
+  NS_ASSERT (CheckInternalState ());
+  if (m_zeroAreaEnd != 0) 
     {
-      NS_ASSERT (m_data->m_initialStart >= m_start);
-      NS_ASSERT (m_size >= (m_data->m_initialStart - m_start));
       Buffer tmp;
-      tmp.AddAtStart (m_zeroAreaSize);
-      tmp.Begin ().WriteU8 (0, m_zeroAreaSize);
-      uint32_t dataStart = m_data->m_initialStart - m_start;
+      tmp.AddAtStart (m_zeroAreaEnd - m_zeroAreaStart);
+      tmp.Begin ().WriteU8 (0, m_zeroAreaEnd - m_zeroAreaStart);
+      uint32_t dataStart = m_zeroAreaStart - m_start;
       tmp.AddAtStart (dataStart);
       tmp.Begin ().Write (m_data->m_data+m_start, dataStart);
-      uint32_t dataEnd = m_size - (m_data->m_initialStart - m_start);
+      uint32_t dataEnd = m_end - m_zeroAreaEnd;
       tmp.AddAtEnd (dataEnd);
       Buffer::Iterator i = tmp.End ();
       i.Prev (dataEnd);
-      i.Write (m_data->m_data+m_data->m_initialStart,dataEnd);
+      i.Write (m_data->m_data+m_zeroAreaStart,dataEnd);
       return tmp;
     }
+  NS_ASSERT (CheckInternalState ());
   return *this;
 }
 
 void
 Buffer::TransformIntoRealBuffer (void) const
 {
+  NS_ASSERT (CheckInternalState ());
   Buffer tmp = CreateFullCopy ();
   *const_cast<Buffer *> (this) = tmp;
+  NS_ASSERT (CheckInternalState ());
 }
 
 
 uint8_t const*
 Buffer::PeekData (void) const
 {
+  NS_ASSERT (CheckInternalState ());
   TransformIntoRealBuffer ();
+  NS_ASSERT (CheckInternalState ());
   return m_data->m_data + m_start;
 }
 
+/******************************************************
+ *            The buffer iterator below.
+ ******************************************************/
+
+
+Buffer::Iterator::Iterator ()
+  : m_zeroStart (0),
+    m_zeroEnd (0),
+    m_dataStart (0),
+    m_dataEnd (0),
+    m_current (0),
+    m_data (0)
+{}
+Buffer::Iterator::Iterator (Buffer const*buffer)
+{
+  Construct (buffer);
+  m_current = m_dataStart;
+}
+Buffer::Iterator::Iterator (Buffer const*buffer, bool dummy)
+{
+  Construct (buffer);
+  m_current = m_dataEnd;
+}
+
+void
+Buffer::Iterator::Construct (const Buffer *buffer)
+{
+  m_zeroStart = buffer->m_zeroAreaStart;
+  m_zeroEnd = buffer->m_zeroAreaEnd;
+  m_dataStart = buffer->m_start;
+  m_dataEnd = buffer->m_end;
+  m_data = buffer->m_data->m_data;
+}
+
+void 
+Buffer::Iterator::Next (void)
+{
+  NS_ASSERT (m_current + 1 <= m_dataEnd);
+  m_current++;
+}
+void 
+Buffer::Iterator::Prev (void)
+{
+  NS_ASSERT (m_current >= 1);
+  m_current--;
+}
+void 
+Buffer::Iterator::Next (uint32_t delta)
+{
+  NS_ASSERT (m_current + delta <= m_dataEnd);
+  m_current += delta;
+}
+void 
+Buffer::Iterator::Prev (uint32_t delta)
+{
+  NS_ASSERT (m_current >= delta);
+  m_current -= delta;
+}
+uint32_t
+Buffer::Iterator::GetDistanceFrom (Iterator const &o) const
+{
+  NS_ASSERT (m_data == o.m_data);
+  int32_t diff = m_current - o.m_current;
+  if (diff < 0)
+    {
+      return -diff;
+    }
+  else
+    {
+      return diff;
+    }
+}
+
+bool 
+Buffer::Iterator::IsEnd (void) const
+{
+  return m_current == m_dataEnd;
+}
+bool 
+Buffer::Iterator::IsStart (void) const
+{
+  return m_current == m_dataStart;
+}
+
+bool 
+Buffer::Iterator::CheckNoZero (uint32_t start, uint32_t end) const
+{
+  bool ok = true;
+  for (uint32_t i = start; i < end; i++)
+    {
+      if (!Check (i))
+        {
+          ok = false;
+        }
+    }
+  return ok;
+}
+bool 
+Buffer::Iterator::Check (uint32_t i) const
+{
+  return i >= m_dataStart && 
+    !(i >= m_zeroStart && i < m_zeroEnd) &&
+    i <= m_dataEnd;
+}
 
 
+void 
+Buffer::Iterator::Write (Iterator start, Iterator end)
+{
+  NS_ASSERT (start.m_data == end.m_data);
+  NS_ASSERT (start.m_current <= end.m_current);
+  NS_ASSERT (start.m_zeroStart == end.m_zeroStart);
+  NS_ASSERT (start.m_zeroEnd == end.m_zeroEnd);
+  NS_ASSERT (m_data != start.m_data);
+  uint32_t size = end.m_current - start.m_current;
+  Iterator cur = start;
+  for (uint32_t i = 0; i < size; i++)
+    {
+      uint8_t data = cur.ReadU8 ();
+      WriteU8 (data);
+    }
+}
 
-}; // namespace ns3
+void 
+Buffer::Iterator::WriteU16 (uint16_t data)
+{
+  WriteU8 (data & 0xff);
+  data >>= 8;
+  WriteU8 (data & 0xff);
+}
+void 
+Buffer::Iterator::WriteU32 (uint32_t data)
+{
+  WriteU8 (data & 0xff);
+  data >>= 8;
+  WriteU8 (data & 0xff);
+  data >>= 8;
+  WriteU8 (data & 0xff);
+  data >>= 8;
+  WriteU8 (data & 0xff);
+}
+void 
+Buffer::Iterator::WriteU64 (uint64_t data)
+{
+  WriteU8 (data & 0xff);
+  data >>= 8;
+  WriteU8 (data & 0xff);
+  data >>= 8;
+  WriteU8 (data & 0xff);
+  data >>= 8;
+  WriteU8 (data & 0xff);
+  data >>= 8;
+  WriteU8 (data & 0xff);
+  data >>= 8;
+  WriteU8 (data & 0xff);
+  data >>= 8;
+  WriteU8 (data & 0xff);
+  data >>= 8;
+  WriteU8 (data & 0xff);
+}
+void 
+Buffer::Iterator::WriteHtonU16 (uint16_t data)
+{
+  WriteU8 ((data >> 8) & 0xff);
+  WriteU8 ((data >> 0) & 0xff);
+}
+void 
+Buffer::Iterator::WriteHtonU32 (uint32_t data)
+{
+  WriteU8 ((data >> 24) & 0xff);
+  WriteU8 ((data >> 16) & 0xff);
+  WriteU8 ((data >> 8) & 0xff);
+  WriteU8 ((data >> 0) & 0xff);
+}
+void 
+Buffer::Iterator::WriteHtonU64 (uint64_t data)
+{
+  WriteU8 ((data >> 56) & 0xff);
+  WriteU8 ((data >> 48) & 0xff);
+  WriteU8 ((data >> 40) & 0xff);
+  WriteU8 ((data >> 32) & 0xff);
+  WriteU8 ((data >> 24) & 0xff);
+  WriteU8 ((data >> 16) & 0xff);
+  WriteU8 ((data >> 8) & 0xff);
+  WriteU8 ((data >> 0) & 0xff);
+}
+void 
+Buffer::Iterator::Write (uint8_t const*buffer, uint32_t size)
+{
+  for (uint32_t i = 0; i < size; i++)
+    {
+      WriteU8 (buffer[i]);
+    }
+}
+
+uint16_t 
+Buffer::Iterator::ReadU16 (void)
+{
+  uint8_t byte0 = ReadU8 ();
+  uint8_t byte1 = ReadU8 ();
+  uint16_t data = byte1;
+  data <<= 8;
+  data |= byte0;
+
+  return data;
+}
+uint32_t 
+Buffer::Iterator::ReadU32 (void)
+{
+  uint8_t byte0 = ReadU8 ();
+  uint8_t byte1 = ReadU8 ();
+  uint8_t byte2 = ReadU8 ();
+  uint8_t byte3 = ReadU8 ();
+  uint32_t data = byte3;
+  data <<= 8;
+  data |= byte2;
+  data <<= 8;
+  data |= byte1;
+  data <<= 8;
+  data |= byte0;
+  return data;
+}
+uint64_t 
+Buffer::Iterator::ReadU64 (void)
+{
+  uint8_t byte0 = ReadU8 ();
+  uint8_t byte1 = ReadU8 ();
+  uint8_t byte2 = ReadU8 ();
+  uint8_t byte3 = ReadU8 ();
+  uint8_t byte4 = ReadU8 ();
+  uint8_t byte5 = ReadU8 ();
+  uint8_t byte6 = ReadU8 ();
+  uint8_t byte7 = ReadU8 ();
+  uint32_t data = byte7;
+  data <<= 8;
+  data |= byte6;
+  data <<= 8;
+  data |= byte5;
+  data <<= 8;
+  data |= byte4;
+  data <<= 8;
+  data |= byte3;
+  data <<= 8;
+  data |= byte2;
+  data <<= 8;
+  data |= byte1;
+  data <<= 8;
+  data |= byte0;
+
+  return data;
+}
+uint16_t 
+Buffer::Iterator::ReadNtohU16 (void)
+{
+  uint16_t retval = 0;
+  retval |= ReadU8 ();
+  retval <<= 8;
+  retval |= ReadU8 ();
+  return retval;
+}
+uint32_t 
+Buffer::Iterator::ReadNtohU32 (void)
+{
+  uint32_t retval = 0;
+  retval |= ReadU8 ();
+  retval <<= 8;
+  retval |= ReadU8 ();
+  retval <<= 8;
+  retval |= ReadU8 ();
+  retval <<= 8;
+  retval |= ReadU8 ();
+  return retval;
+}
+uint64_t 
+Buffer::Iterator::ReadNtohU64 (void)
+{
+  uint64_t retval = 0;
+  retval |= ReadU8 ();
+  retval <<= 8;
+  retval |= ReadU8 ();
+  retval <<= 8;
+  retval |= ReadU8 ();
+  retval <<= 8;
+  retval |= ReadU8 ();
+  retval <<= 8;
+  retval |= ReadU8 ();
+  retval <<= 8;
+  retval |= ReadU8 ();
+  retval <<= 8;
+  retval |= ReadU8 ();
+  retval <<= 8;
+  retval |= ReadU8 ();
+  return retval;
+}
+void 
+Buffer::Iterator::Read (uint8_t *buffer, uint32_t size)
+{
+  for (uint32_t i = 0; i < size; i++)
+    {
+      buffer[i] = ReadU8 ();
+    }
+}
+
+#ifndef BUFFER_USE_INLINE
+
+void 
+Buffer::Iterator::WriteU8  (uint8_t  data)
+{
+  if (m_current < m_dataStart)
+    {
+      // XXX trying to write outside of data area
+      NS_ASSERT (false);
+    }
+  else if (m_current < m_zeroStart)
+    {
+      m_data[m_current] = data;
+      m_current++;
+    }
+  else if (m_current < m_zeroEnd)
+    {
+      // XXX trying to write in zero area
+      NS_ASSERT (false);
+    }
+  else if (m_current < m_dataEnd)
+    {
+      m_data[m_current - (m_zeroEnd-m_zeroStart)] = data;
+      m_current++;      
+    }
+  else 
+    {
+      // XXX trying to write outside of data area
+      NS_ASSERT (false);
+    }
+}
+
+void 
+Buffer::Iterator::WriteU8 (uint8_t  data, uint32_t len)
+{
+  for (uint32_t i = 0; i < len; i++)
+    {
+      WriteU8 (data);
+    }
+}
+
+uint8_t  
+Buffer::Iterator::ReadU8 (void)
+{
+  if (m_current < m_dataStart)
+    {
+      // XXX trying to read from outside of data area
+      NS_ASSERT (false);
+    }
+  else if (m_current < m_zeroStart)
+    {
+      uint8_t data = m_data[m_current];
+      m_current++;
+      return data;
+    }
+  else if (m_current < m_zeroEnd)
+    {
+      m_current++;
+      return 0;
+    }
+  else if (m_current < m_dataEnd)
+    {
+      uint8_t data = m_data[m_current - (m_zeroEnd-m_zeroStart)];
+      m_current++;
+      return data;
+    }
+  else 
+    {
+      // XXX trying to read from outside of data area
+      NS_ASSERT (false);
+    }
+  // to quiet compiler.
+  return 0;
+}
+
+#endif /* BUFFER_USE_INLINE */
+
+} // namespace ns3
 
 
 #ifdef RUN_SELF_TESTS
@@ -460,6 +990,7 @@
 #include "ns3/random-variable.h"
 #include <iomanip>
 
+
 namespace ns3 {
 
 class BufferTest: public Test {
@@ -687,6 +1218,13 @@
   i.Prev (100);
   i.WriteU8 (1, 100);
 
+#if 0
+  buffer = Buffer (10);  
+  ENSURE_WRITTEN_BYTES (buffer, 10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+  buffer.Begin ().WriteU8 (1);
+  ENSURE_WRITTEN_BYTES (buffer, 10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+#endif
+
   // Bug #54
   {
     const uint32_t actualSize = 72602;
@@ -718,7 +1256,7 @@
 
 static BufferTest gBufferTest;
 
-}; // namespace ns3
+} // namespace ns3
 
 #endif /* RUN_SELF_TESTS */
 
--- a/src/common/buffer.h	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/common/buffer.h	Wed Sep 12 18:06:09 2007 +0100
@@ -1,7 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2005,2006 INRIA
- * All rights reserved.
+ * Copyright (c) 2005,2006,2007 INRIA
  *
  * 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
@@ -24,6 +23,16 @@
 #include <stdint.h>
 #include <vector>
 
+#define BUFFER_HEURISTICS 1
+#define BUFFER_USE_INLINE 1
+
+
+#ifdef BUFFER_USE_INLINE
+#define BUFFER_INLINE inline
+#else
+#define BUFFER_INLINE
+#endif
+
 namespace ns3 {
 
 /**
@@ -36,6 +45,51 @@
  * by creating new Buffers of the maximum size ever used.
  * The correct maximum size is learned at runtime during use by 
  * recording the maximum size of each packet.
+ *
+ * \internal
+ * The implementation of the Buffer class uses a COW (Copy On Write)
+ * technique to ensure that the underlying data buffer which holds
+ * the data bytes is shared among a lot of Buffer instances despite
+ * data being added or removed from them.
+ *
+ * When multiple Buffer instances hold a reference to the same 
+ * underlying BufferData object, they must be able to detect when
+ * the operation they want to perform should trigger a copy of the
+ * BufferData. If the BufferData::m_count field is one, it means that
+ * there exist only one instance of Buffer which references the 
+ * BufferData instance so, it is safe to modify it. It is also
+ * safe to modify the content of a BufferData if the modification
+ * falls outside of the "dirty area" defined by the BufferData.
+ * In every other case, the BufferData must be copied before
+ * being modified.
+ *
+ * To understand the way the Buffer::Add and Buffer::Remove methods
+ * work, you first need to understand the "virtual offsets" used to
+ * keep track of the content of buffers. Each Buffer instance
+ * contains real data bytes in its BufferData instance but it also
+ * contains "virtual zero data" which typically is used to represent
+ * application-level payload. No memory is allocated to store the
+ * zero bytes of application-level payload unless the user fragments
+ * a Buffer: this application-level payload is kept track of with
+ * a pair of integers which describe where in the buffer content
+ * the "virtual zero area" starts and ends.
+ *
+ * ***: unused bytes
+ * xxx: bytes "added" at the front of the zero area
+ * ...: bytes "added" at the back of the zero area
+ * 000: virtual zero bytes
+ *
+ * Real byte buffer:      |********xxxxxxxxxxxx.........*****|
+ *                        |--------^ m_start
+ *                        |-------------------^ m_zeroAreaStart
+ *                        |-----------------------------^ m_end - (m_zeroAreaEnd - m_zeroAreaStart)
+ * virtual byte buffer:           |xxxxxxxxxxxx0000000000000.........|
+ *                        |--------^ m_start
+ *                        |--------------------^ m_zeroAreaStart
+ *                        |---------------------------------^ m_zeroAreaEnd
+ *                        |------------------------------------------^ m_end
+ *
+ * A simple state invariant is that m_start <= m_zeroStart <= m_zeroEnd <= m_end
  */
 class Buffer {
 public:
@@ -44,23 +98,23 @@
    */
   class Iterator {
   public:
-      inline Iterator ();
+      Iterator ();
       /**
        * go forward by one byte
        */
-      inline void Next (void);
+      void Next (void);
       /**
        * go backward by one byte
        */
-      inline void Prev (void);
+      void Prev (void);
       /**
        * \param delta number of bytes to go forward
        */
-      inline void Next (uint32_t delta);
+      void Next (uint32_t delta);
       /**
        * \param delta number of bytes to go backward
        */
-      inline void Prev (uint32_t delta);
+      void Prev (uint32_t delta);
       /**
        * \param o the second iterator
        * \return number of bytes included between the two iterators
@@ -69,18 +123,18 @@
        * to the same underlying buffer. Debug builds ensure
        * this with an assert.
        */
-      inline uint32_t GetDistanceFrom (Iterator const &o) const;
+      uint32_t GetDistanceFrom (Iterator const &o) const;
       
       /**
        * \return true if this iterator points to the end of the byte array.
        *     false otherwise.
        */
-      inline bool IsEnd (void) const;
+      bool IsEnd (void) const;
       /**
        * \return true if this iterator points to the start of the byte array.
        *     false otherwise.
        */
-      inline bool IsStart (void) const;
+      bool IsStart (void) const;
 
       /**
        * \param data data to write in buffer
@@ -88,7 +142,7 @@
        * Write the data in buffer and avance the iterator position
        * by one byte.
        */
-      inline void WriteU8 (uint8_t  data);
+      BUFFER_INLINE void WriteU8 (uint8_t  data);
       /**
        * \param data data to write in buffer
        * \param len number of times data must be written in buffer
@@ -96,7 +150,7 @@
        * Write the data in buffer len times and avance the iterator position
        * by len byte.
        */
-      inline void WriteU8 (uint8_t data, uint32_t len);
+      BUFFER_INLINE void WriteU8 (uint8_t data, uint32_t len);
       /**
        * \param data data to write in buffer
        *
@@ -106,7 +160,7 @@
        * return exactly what we wrote with writeU16 if the program
        * is run on the same machine.
        */
-      inline void WriteU16 (uint16_t data);
+      void WriteU16 (uint16_t data);
       /**
        * \param data data to write in buffer
        *
@@ -116,7 +170,7 @@
        * return exactly what we wrote with writeU32 if the program
        * is run on the same machine.
        */
-      inline void WriteU32 (uint32_t data);
+      void WriteU32 (uint32_t data);
       /**
        * \param data data to write in buffer
        *
@@ -126,7 +180,7 @@
        * return exactly what we wrote with writeU64 if the program
        * is run on the same machine.
        */
-      inline void WriteU64 (uint64_t data);
+      void WriteU64 (uint64_t data);
       /**
        * \param data data to write in buffer
        *
@@ -134,7 +188,7 @@
        * by two bytes. The data is written in network order and the
        * input data is expected to be in host order.
        */
-      inline void WriteHtonU16 (uint16_t data);
+      void WriteHtonU16 (uint16_t data);
       /**
        * \param data data to write in buffer
        *
@@ -142,7 +196,7 @@
        * by four bytes. The data is written in network order and the
        * input data is expected to be in host order.
        */
-      inline void WriteHtonU32 (uint32_t data);
+      void WriteHtonU32 (uint32_t data);
       /**
        * \param data data to write in buffer
        *
@@ -150,7 +204,7 @@
        * by eight bytes. The data is written in network order and the
        * input data is expected to be in host order.
        */
-      inline void WriteHtonU64 (uint64_t data);
+      void WriteHtonU64 (uint64_t data);
       /**
        * \param buffer a byte buffer to copy in the internal buffer.
        * \param size number of bytes to copy.
@@ -158,7 +212,7 @@
        * Write the data in buffer and avance the iterator position
        * by size bytes.
        */
-      inline void Write (uint8_t const*buffer, uint32_t size);
+      void Write (uint8_t const*buffer, uint32_t size);
       /**
        * \param start the start of the data to copy
        * \param end the end of the data to copy
@@ -170,7 +224,7 @@
        * we do to avoid overlapping copies. This is enforced 
        * in debug builds by asserts.
        */
-      inline void Write (Iterator start, Iterator end);
+      void Write (Iterator start, Iterator end);
 
       /**
        * \return the byte read in the buffer.
@@ -178,7 +232,7 @@
        * Read data and advance the Iterator by the number of bytes
        * read.
        */
-      inline uint8_t  ReadU8 (void);
+      BUFFER_INLINE uint8_t  ReadU8 (void);
       /**
        * \return the two bytes read in the buffer.
        *
@@ -186,7 +240,7 @@
        * read.
        * The data is read in the format written by writeU16.
        */
-      inline uint16_t ReadU16 (void);
+      uint16_t ReadU16 (void);
       /**
        * \return the four bytes read in the buffer.
        *
@@ -194,7 +248,7 @@
        * read.
        * The data is read in the format written by writeU32.
        */
-      inline uint32_t ReadU32 (void);
+      uint32_t ReadU32 (void);
       /**
        * \return the eight bytes read in the buffer.
        *
@@ -202,7 +256,7 @@
        * read.
        * The data is read in the format written by writeU64.
        */
-      inline uint64_t ReadU64 (void);
+      uint64_t ReadU64 (void);
       /**
        * \return the two bytes read in the buffer.
        *
@@ -210,7 +264,7 @@
        * read.
        * The data is read in network format and return in host format.
        */
-      inline uint16_t ReadNtohU16 (void);
+      uint16_t ReadNtohU16 (void);
       /**
        * \return the four bytes read in the buffer.
        *
@@ -218,7 +272,7 @@
        * read.
        * The data is read in network format and return in host format.
        */
-      inline uint32_t ReadNtohU32 (void);
+      uint32_t ReadNtohU32 (void);
       /**
        * \return the eight bytes read in the buffer.
        *
@@ -226,7 +280,7 @@
        * read.
        * The data is read in network format and return in host format.
        */
-      inline uint64_t ReadNtohU64 (void);
+      uint64_t ReadNtohU64 (void);
       /**
        * \param buffer buffer to copy data into
        * \param size number of bytes to copy
@@ -235,22 +289,45 @@
        * input buffer and avance the Iterator by the number of
        * bytes read.
        */
-      inline void Read (uint8_t *buffer, uint16_t size);
+      void Read (uint8_t *buffer, uint32_t size);
   private:
       friend class Buffer;
-      inline Iterator (Buffer const*buffer, uint32_t m_current);
-      inline uint32_t GetIndex (uint32_t n);
+      Iterator (Buffer const*buffer);
+      Iterator (Buffer const*buffer, bool);
+      void Construct (const Buffer *buffer);
+      bool CheckNoZero (uint32_t start, uint32_t end) const;
+      bool Check (uint32_t i) const;
+
+    /* offset in virtual bytes from the start of the data buffer to the
+     * start of the "virtual zero area".
+     */
       uint32_t m_zeroStart;
+    /* offset in virtual bytes from the start of the data buffer to the
+     * end of the "virtual zero area".
+     */
       uint32_t m_zeroEnd;
+    /* offset in virtual bytes from the start of the data buffer to the
+     * start of the data which can be read by this iterator
+     */
+      uint32_t m_dataStart;
+    /* offset in virtual bytes from the start of the data buffer to the
+     * end of the data which can be read by this iterator
+     */
       uint32_t m_dataEnd;
+    /* offset in virtual bytes from the start of the data buffer to the
+     * current position represented by this iterator.
+     */
       uint32_t m_current;
+    /* a pointer to the underlying byte buffer. All offsets are relative
+     * to this pointer.
+     */
       uint8_t *m_data;
   };
 
   /**
    * \return the number of bytes stored in this buffer.
    */
-  inline uint32_t GetSize (void) const;
+  uint32_t GetSize (void) const;
 
   /**
    * \return a pointer to the start of the internal 
@@ -313,409 +390,135 @@
    * \return an Iterator which points to the
    * start of this Buffer.
    */
-  inline Buffer::Iterator Begin (void) const;
+  Buffer::Iterator Begin (void) const;
   /**
    * \return an Iterator which points to the
    * end of this Buffer.
    */
-  inline Buffer::Iterator End (void) const;
+  Buffer::Iterator End (void) const;
 
   Buffer CreateFullCopy (void) const;
 
-  inline Buffer (Buffer const &o);
-  inline Buffer &operator = (Buffer const &o);
-  inline Buffer ();
-  inline Buffer (uint32_t dataSize);
-  inline ~Buffer ();
+  Buffer (Buffer const &o);
+  Buffer &operator = (Buffer const &o);
+  Buffer ();
+  Buffer (uint32_t dataSize);
+  ~Buffer ();
 private:
-  struct BufferData {
-      uint32_t m_count;
-      uint32_t m_size;
-      uint32_t m_initialStart;
-      uint32_t m_dirtyStart;
-      uint32_t m_dirtySize;
-      uint8_t m_data[1];
-  };
-  class BufferDataList : public std::vector<struct Buffer::BufferData*>
-  {
-  public:
-    ~BufferDataList ();
-  };
+
+  void TransformIntoRealBuffer (void) const;
+  bool CheckInternalState (void) const;
+  void Initialize (uint32_t zeroSize);
+  uint32_t GetInternalSize (void) const;
+  uint32_t GetInternalEnd (void) const;
+  static void Recycle (struct BufferData *data);
+  static struct BufferData *Create (uint32_t size);
 
-  inline uint8_t *GetStart (void) const;
-  void TransformIntoRealBuffer (void) const;
-  static void Recycle (struct Buffer::BufferData *data);
-  static struct Buffer::BufferData *Create (void);
-  static struct Buffer::BufferData *Allocate (uint32_t size, uint32_t start);
-  static void Deallocate (struct Buffer::BufferData *data);
-
-  static BufferDataList m_freeList;
-  static uint32_t m_maxTotalAddStart;
-  static uint32_t m_maxTotalAddEnd;
-
+  /* This structure is described in the buffer.cc file.
+   */
   struct BufferData *m_data;
-  uint32_t m_zeroAreaSize;
+#ifdef BUFFER_HEURISTICS
+  /* keep track of the maximum value of m_zeroAreaStart across
+   * the lifetime of a Buffer instance. This variable is used
+   * purely as a source of information for the heuristics which
+   * decide on the position of the zero area in new buffers.
+   * It is read from the Buffer destructor to update the global
+   * heuristic data and these global heuristic data are used from
+   * the Buffer constructor to choose an initial value for 
+   * m_zeroAreaStart.
+   * It is possible to disable all these heuristics by undefining the
+   * BUFFER_HEURISTICS macro at the top of buffer.h
+   */
+  uint32_t m_maxZeroAreaStart;
+#endif /* BUFFER_HEURISTICS */
+  /* offset to the start of the virtual zero area from the start 
+   * of m_data->m_data
+   */
+  uint32_t m_zeroAreaStart;
+  /* offset to the end of the virtual zero area from the start 
+   * of m_data->m_data
+   */
+  uint32_t m_zeroAreaEnd;
+  /* offset to the start of the data referenced by this Buffer
+   * instance from the start of m_data->m_data
+   */
   uint32_t m_start;
-  uint32_t m_size;
+  /* offset to the end of the data referenced by this Buffer
+   * instance from the start of m_data->m_data
+   */
+  uint32_t m_end;
 };
 
-}; // namespace ns3
-
+} // namespace ns3
 
-/**************************************************
-   Start of implementation of methods which 
-   need to be inline for performance reasons.
- *************************************************/
+#ifdef BUFFER_USE_INLINE
 
 #include "ns3/assert.h"
 
 namespace ns3 {
 
-Buffer::Buffer ()
-  : m_data (Buffer::Create ()),
-    m_zeroAreaSize (0),
-    m_start (m_maxTotalAddStart),
-    m_size (0)
-{
-  if (m_start > m_data->m_size) 
-    {
-      m_start = 0;
-    }
-  NS_ASSERT (m_start <= m_data->m_size);
-}
-
-Buffer::Buffer (uint32_t dataSize)
-  : m_data (Buffer::Create ()),
-    m_zeroAreaSize (dataSize),
-    m_start (m_maxTotalAddStart),
-    m_size (0)
-{
-  if (m_start > m_data->m_size) 
-    {
-      m_start = 0;
-    }
-  NS_ASSERT (m_start <= m_data->m_size);
-}
-
-
-Buffer::Buffer (Buffer const&o)
-  : m_data (o.m_data),
-    m_zeroAreaSize (o.m_zeroAreaSize),
-    m_start (o.m_start),
-    m_size (o.m_size)
-{
-  m_data->m_count++;
-  NS_ASSERT (m_start <= m_data->m_size);
-}
-
-Buffer &
-Buffer::operator = (Buffer const&o)
-{
-  if (m_data != o.m_data) 
-    {
-      // not assignment to self.
-      m_data->m_count--;
-      if (m_data->m_count == 0) 
-        {
-          Recycle (m_data);
-        }
-      m_data = o.m_data;
-      m_data->m_count++;
-    }
-  m_zeroAreaSize = o.m_zeroAreaSize;
-  m_start = o.m_start;
-  m_size = o.m_size;
-  NS_ASSERT (m_start <= m_data->m_size);
-  return *this;
-}
-
-Buffer::~Buffer ()
-{
-  m_data->m_count--;
-  if (m_data->m_count == 0) 
-    {
-      Recycle (m_data);
-    }
-}
-
-
-uint8_t *
-Buffer::GetStart (void) const
+void
+Buffer::Iterator::WriteU8 (uint8_t data)
 {
-  return m_data->m_data + m_start;
-}
-
-uint32_t 
-Buffer::GetSize (void) const
-{
-  return m_size + m_zeroAreaSize;
-}
-
-Buffer::Iterator 
-Buffer::Begin (void) const
-{
-  return Buffer::Iterator (this, 0);
-}
-Buffer::Iterator 
-Buffer::End (void) const
-{
-  return Buffer::Iterator (this, GetSize ());
-}
-
+  NS_ASSERT (Check (m_current));
 
-Buffer::Iterator::Iterator ()
-  : m_zeroStart (0),
-    m_zeroEnd (0),
-    m_dataEnd (0),
-    m_current (0),
-    m_data (0)
-{}
-Buffer::Iterator::Iterator (Buffer const*buffer, uint32_t current)
-  : m_zeroStart (buffer->m_data->m_initialStart-buffer->m_start),
-    m_zeroEnd (m_zeroStart+buffer->m_zeroAreaSize),
-    m_dataEnd (buffer->GetSize ()),
-    m_current (current),
-    m_data (buffer->m_data->m_data+buffer->m_start)
-{}
-
-void 
-Buffer::Iterator::Next (void)
-{
-  NS_ASSERT (m_current + 1 <= m_dataEnd);
-  m_current++;
-}
-void 
-Buffer::Iterator::Prev (void)
-{
-  NS_ASSERT (m_current >= 1);
-  m_current--;
-}
-void 
-Buffer::Iterator::Next (uint32_t delta)
-{
-  NS_ASSERT (m_current + delta <= m_dataEnd);
-  m_current += delta;
-}
-void 
-Buffer::Iterator::Prev (uint32_t delta)
-{
-  NS_ASSERT (m_current >= delta);
-  m_current -= delta;
-}
-uint32_t
-Buffer::Iterator::GetDistanceFrom (Iterator const &o) const
-{
-  NS_ASSERT (m_data == o.m_data);
-  int32_t start = m_current;
-  int32_t end = o.m_current;
-  int32_t diff = end - start;
-  if (diff < 0)
+  if (m_current < m_zeroStart)
     {
-      return -diff;
+      m_data[m_current] = data;
+      m_current++;
     }
   else
     {
-      return diff;
+      m_data[m_current - (m_zeroEnd-m_zeroStart)] = data;
+      m_current++;      
     }
 }
 
-bool 
-Buffer::Iterator::IsEnd (void) const
-{
-  return m_current == m_dataEnd;
-}
-bool 
-Buffer::Iterator::IsStart (void) const
-{
-  return m_current == 0;
-}
-
-uint32_t
-Buffer::Iterator::GetIndex (uint32_t n)
-{
-  NS_ASSERT ( 
-      (m_current + n <= m_dataEnd) &&
-      ((m_current + n <= m_zeroStart) ||
-       (m_current >= m_zeroEnd) ||
-       m_zeroStart == m_zeroEnd)
-      );
-  uint32_t index;
-  if (m_current < m_zeroStart) 
-    {
-      index = m_current;
-    } 
-  else 
-    {
-      index = m_current - (m_zeroEnd-m_zeroStart);
-    }
-  return index;
-}
-
-
-void 
-Buffer::Iterator::Write (Iterator start, Iterator end)
-{
-  NS_ASSERT (start.m_data == end.m_data);
-  NS_ASSERT (start.m_current <= end.m_current);
-  NS_ASSERT (start.m_zeroStart == end.m_zeroStart);
-  NS_ASSERT (start.m_zeroEnd == end.m_zeroEnd);
-  NS_ASSERT (m_data != start.m_data);
-  uint32_t size = end.m_current - start.m_current;
-  uint8_t *src = start.m_data + start.GetIndex (size);
-  uint8_t *dest = m_data + GetIndex (size);
-  memcpy (dest, src, size);
-  m_current += size;
-}
-
 void 
 Buffer::Iterator::WriteU8 (uint8_t  data, uint32_t len)
 {
-  uint8_t *current = m_data + GetIndex (len);
-  memset (current, data, len);
-  m_current += len;
-}
-void 
-Buffer::Iterator::WriteU8  (uint8_t  data)
-{
-  m_data[GetIndex (1)] = data;
-  m_current++;
-}
-void 
-Buffer::Iterator::WriteU16 (uint16_t data)
-{
-  uint16_t *buffer = (uint16_t *)(m_data + GetIndex (2));
-  *buffer = data;
-  m_current += 2;
-}
-void 
-Buffer::Iterator::WriteU32 (uint32_t data)
-{
-  uint32_t *buffer = (uint32_t *)(m_data + GetIndex (4));
-  *buffer = data;
-  m_current += 4;
-}
-void 
-Buffer::Iterator::WriteU64 (uint64_t data)
-{
-  uint64_t *buffer = (uint64_t *)(m_data + GetIndex (8));
-  *buffer = data;
-  m_current += 8;
-}
-void 
-Buffer::Iterator::WriteHtonU16 (uint16_t data)
-{
-  uint8_t *current = m_data + GetIndex (2);
-  *(current+0) = (data >> 8) & 0xff;
-  *(current+1) = (data >> 0) & 0xff;
-  m_current += 2;
-}
-void 
-Buffer::Iterator::WriteHtonU32 (uint32_t data)
-{
-  uint8_t *current = m_data + GetIndex (4);
-  *(current+0) = (data >> 24) & 0xff;
-  *(current+1) = (data >> 16) & 0xff;
-  *(current+2) = (data >> 8) & 0xff;
-  *(current+3) = (data >> 0) & 0xff;
-  m_current += 4;
-}
-void 
-Buffer::Iterator::WriteHtonU64 (uint64_t data)
-{
-  uint8_t *current = m_data + GetIndex (8);
-  *(current+0) = (data >> 56) & 0xff;
-  *(current+1) = (data >> 48) & 0xff;
-  *(current+2) = (data >> 40) & 0xff;
-  *(current+3) = (data >> 32) & 0xff;
-  *(current+4) = (data >> 24) & 0xff;
-  *(current+5) = (data >> 16) & 0xff;
-  *(current+6) = (data >> 8) & 0xff;
-  *(current+7) = (data >> 0) & 0xff;
-  m_current += 8;
-}
-void 
-Buffer::Iterator::Write (uint8_t const*buffer, uint32_t size)
-{
-  uint8_t *current = m_data + GetIndex (size);
-  memcpy (current, buffer, size);
-  m_current += size;
+  NS_ASSERT (CheckNoZero (m_current, m_current + len));
+  if (m_current <= m_zeroStart)
+    {
+      memset (&(m_data[m_current]), data, len);
+      m_current += len;
+    }
+  else
+    {
+      uint8_t *buffer = &m_data[m_current - (m_zeroEnd-m_zeroStart)];
+      memset (buffer, data, len);
+      m_current += len;
+    }
 }
 
 uint8_t  
 Buffer::Iterator::ReadU8 (void)
 {
-  uint8_t data = m_data[GetIndex(1)];
-  m_current++;
-  return data;
-}
-uint16_t 
-Buffer::Iterator::ReadU16 (void)
-{
-  uint16_t *buffer = reinterpret_cast<uint16_t *>(m_data + GetIndex (2));
-  m_current += 2;
-  return *buffer;
-}
-uint32_t 
-Buffer::Iterator::ReadU32 (void)
-{
-  uint32_t *buffer = reinterpret_cast<uint32_t *>(m_data + GetIndex (4));
-  m_current += 4;
-  return *buffer;
-}
-uint64_t 
-Buffer::Iterator::ReadU64 (void)
-{
-  uint64_t *buffer = reinterpret_cast<uint64_t *>(m_data + GetIndex (8));
-  m_current += 8;
-  return *buffer;
-}
-uint16_t 
-Buffer::Iterator::ReadNtohU16 (void)
-{
-  uint8_t *current = m_data + GetIndex (2);
-  uint16_t retval = 0;
-  retval |= static_cast<uint16_t> (current[0]) << 8;
-  retval |= static_cast<uint16_t> (current[1]) << 0;
-  m_current += 2;
-  return retval;
-}
-uint32_t 
-Buffer::Iterator::ReadNtohU32 (void)
-{
-  uint8_t *current = m_data + GetIndex (4);
-  uint32_t retval = 0;
-  retval |= static_cast<uint32_t> (current[0]) << 24;
-  retval |= static_cast<uint32_t> (current[1]) << 16;
-  retval |= static_cast<uint32_t> (current[2]) << 8;
-  retval |= static_cast<uint32_t> (current[3]) << 0;
-  m_current += 4;
-  return retval;
-}
-uint64_t 
-Buffer::Iterator::ReadNtohU64 (void)
-{
-  uint8_t *current = m_data + GetIndex (8);
-  uint64_t retval = 0;
-  retval |= static_cast<uint64_t> (current[0]) << 56;
-  retval |= static_cast<uint64_t> (current[1]) << 48;
-  retval |= static_cast<uint64_t> (current[2]) << 40;
-  retval |= static_cast<uint64_t> (current[3]) << 32;
-  retval |= static_cast<uint64_t> (current[4]) << 24;
-  retval |= static_cast<uint64_t> (current[5]) << 16;
-  retval |= static_cast<uint64_t> (current[6]) << 8;
-  retval |= static_cast<uint64_t> (current[7]) << 0;
-  m_current += 8;
-  return retval;
-}
-void 
-Buffer::Iterator::Read (uint8_t *buffer, uint16_t size)
-{
-  uint8_t *current = m_data + GetIndex (size);
-  memcpy (buffer, current, size);
-  m_current += size;
+  NS_ASSERT (m_current >= m_dataStart &&
+             m_current <= m_dataEnd);
+
+  if (m_current < m_zeroStart)
+    {
+      uint8_t data = m_data[m_current];
+      m_current++;
+      return data;
+    }
+  else if (m_current < m_zeroEnd)
+    {
+      m_current++;
+      return 0;
+    }
+  else
+    {
+      uint8_t data = m_data[m_current - (m_zeroEnd-m_zeroStart)];
+      m_current++;
+      return data;
+    }
 }
 
-}; // namespace ns3
 
+} // namespace ns3
+
+#endif /* BUFFER_USE_INLINE */
 
 #endif /* BUFFER_H */
--- a/src/common/packet-metadata-test.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/common/packet-metadata-test.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -673,6 +673,13 @@
   p = DoAddHeader (p);
   CHECK_HISTORY (p, 2, 10, 10);
 
+  p = Packet (10);
+  ADD_HEADER (p, 8);
+  ADD_TRAILER (p, 8);
+  ADD_TRAILER (p, 8);
+  p.RemoveAtStart (8+10+8);
+  CHECK_HISTORY (p, 1, 8);
+
   return ok;
 }
 
--- a/src/common/packet.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/common/packet.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -249,7 +249,7 @@
                                  packet.GetSize ());
   if (msg != "hello world")
     {
-      Failure () << "expected size 'hello world', got " << msg << std::endl;
+      Failure () << "expected 'hello world', got '" << msg << "'" << std::endl;
       ok = false;
     }
 
--- a/src/devices/csma/csma-channel.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/devices/csma/csma-channel.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -250,7 +250,7 @@
   }
 
   NS_DEBUG ("CsmaChannel::TransmitEnd (): Schedule event in " << 
-            m_delay.GetSeconds () << "sec");
+            m_delay.GetSeconds () << " sec");
 
   Simulator::Schedule (m_delay,
                        &CsmaChannel::PropagationCompleteEvent,
--- a/src/devices/csma/csma-ipv4-topology.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/devices/csma/csma-ipv4-topology.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -35,82 +35,79 @@
 namespace ns3 {
 
 uint32_t
-CsmaIpv4Topology::AddIpv4CsmaNode(Ptr<Node> n1,
-                                      Ptr<CsmaChannel> ch,
-                                      Eui48Address addr)
+CsmaIpv4Topology::AddIpv4CsmaNetDevice(
+  Ptr<Node> node,
+  Ptr<CsmaChannel> channel,
+  Eui48Address addr)
 {
   Ptr<Queue> q = Queue::CreateDefault ();
 
   // assume full-duplex
-  Ptr<CsmaNetDevice> nd0 = Create<CsmaNetDevice> (n1, addr, 
-                                                      ns3::CsmaNetDevice::IP_ARP,
-                                                      true, true);
-  nd0->AddQueue(q);
-  nd0->Attach (ch);
-  return nd0->GetIfIndex ();
+  Ptr<CsmaNetDevice> nd = Create<CsmaNetDevice> (node, addr, 
+    ns3::CsmaNetDevice::IP_ARP, true, true);
+
+  nd->AddQueue(q);
+  nd->Attach (channel);
+  return nd->GetIfIndex ();
 }
 
 
 void
 CsmaIpv4Topology::AddIpv4LlcCsmaNode(Ptr<Node> n1,
-                                         Ptr<CsmaChannel> ch,
-                                         Eui48Address addr)
+                                     Ptr<CsmaChannel> ch,
+                                     Eui48Address addr)
 {
   Ptr<Queue> q = Queue::CreateDefault ();
 
   Ptr<CsmaNetDevice> nd0 = Create<CsmaNetDevice> (n1, addr,
-                                                      ns3::CsmaNetDevice::LLC,
-                                                      true, false);
+                                                  ns3::CsmaNetDevice::LLC,
+                                                  true, false);
   nd0->AddQueue(q);
   nd0->Attach (ch);
 
   Ptr<CsmaNetDevice> nd1 = Create<CsmaNetDevice> (n1, addr,
-                                                      ns3::CsmaNetDevice::LLC,
-                                                      false, true);
+                                                  ns3::CsmaNetDevice::LLC,
+                                                  false, true);
   nd1->AddQueue(q);
   nd1->Attach (ch);
 }
 
 void
 CsmaIpv4Topology::AddIpv4RawCsmaNode(Ptr<Node> n1,
-                                         Ptr<CsmaChannel> ch,
-                                         Eui48Address addr)
+                                     Ptr<CsmaChannel> ch,
+                                     Eui48Address addr)
 {
   Ptr<Queue> q = Queue::CreateDefault ();
 
   Ptr<CsmaNetDevice> nd0 = Create<CsmaNetDevice> (n1, addr,
-                                                      ns3::CsmaNetDevice::RAW,
-                                                      true, false);
+                                                  ns3::CsmaNetDevice::RAW,
+                                                  true, false);
   nd0->AddQueue(q);
   nd0->Attach (ch);
 
   Ptr<CsmaNetDevice> nd1 = Create<CsmaNetDevice> (n1, addr,
-                                                      ns3::CsmaNetDevice::RAW,
-                                                      false, true);
+                                                  ns3::CsmaNetDevice::RAW,
+                                                  false, true);
   nd1->AddQueue(q);
   nd1->Attach (ch);
 }
 
-void
-CsmaIpv4Topology::AddIpv4Address(Ptr<Node> n1,
-                                       int ndNum,
-                                       const Ipv4Address& addr1,
-                                       const Ipv4Mask& netmask1)
+uint32_t
+CsmaIpv4Topology::AddIpv4Address(
+  Ptr<Node>             node,
+  uint32_t              netDeviceNumber,
+  const Ipv4Address     address,
+  const Ipv4Mask        mask)
 {
+  Ptr<NetDevice> nd = node->GetDevice(netDeviceNumber);
 
-  // Duplex link is assumed to be subnetted as a /30
-  // May run this unnumbered in the future?
-  Ipv4Mask netmask(netmask1);
-
-  Ptr<NetDevice> nd1 = n1->GetDevice(ndNum);
+  Ptr<Ipv4> ipv4 = node->QueryInterface<Ipv4> (Ipv4::iid);
+  uint32_t ifIndex = ipv4->AddInterface (nd);
 
-  Ptr<Ipv4> ip1 = n1->QueryInterface<Ipv4> (Ipv4::iid);
-  uint32_t index1 = ip1->AddInterface (nd1);
-
-  ip1->SetAddress (index1, addr1);
-  ip1->SetNetworkMask (index1, netmask);
-  ip1->SetUp (index1);
-
+  ipv4->SetAddress (ifIndex, address);
+  ipv4->SetNetworkMask (ifIndex, mask);
+  ipv4->SetUp (ifIndex);
+  return ifIndex;
 }
 
 void
@@ -133,7 +130,7 @@
           found = true;
         }
     }
-  NS_ASSERT(found);
+  NS_ASSERT (found);
 
   uint32_t index2 = 0;
   found = false;
@@ -145,7 +142,7 @@
           found = true;
         }
     }
-  NS_ASSERT(found);
+  NS_ASSERT (found);
 
   ip1->AddHostRouteTo (ip2-> GetAddress (index2), index1);
   ip2->AddHostRouteTo (ip1-> GetAddress (index1), index2); 
--- a/src/devices/csma/csma-ipv4-topology.h	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/devices/csma/csma-ipv4-topology.h	Wed Sep 12 18:06:09 2007 +0100
@@ -61,9 +61,9 @@
    * 
    * \return ifIndex of the device
    */
-  static uint32_t AddIpv4CsmaNode( Ptr<Node> n1,
-                                     Ptr<CsmaChannel> ch,
-                                     Eui48Address addr);
+  static uint32_t AddIpv4CsmaNetDevice(Ptr<Node> node,
+                                       Ptr<CsmaChannel> channel,
+                                       Eui48Address addr);
 
   /**
    * \param n1 Node to be attached to the Csma channel
@@ -94,18 +94,23 @@
 
 
   /** 
-   * \param n1 Node
-   * \param ndNum NetDevice number with which to associate address
-   * \param addr1 Ipv4 Address for ndNum of n1
-   * \param netmask1 network mask for ndNum of node n1
+   * \brief Create an Ipv4 interface for a net device and assign an 
+   * Ipv4Address to that interface.
+   *
+   * \param node The node to which to add the new address and corresponding 
+   *        interface.
+   * \param netDeviceNumber The NetDevice index number with which to associate
+   *        the address.
+   * \param address The Ipv4 Address for the interface.
+   * \param network The network mask for the interface
    * 
    * Add an Ipv4Address to the Ipv4 interface associated with the
-   * ndNum CsmaIpv4NetDevices on the provided
-   * CsmaIpv4Channel
+   * ndNum CsmaIpv4NetDevices on the provided CsmaIpv4Channel
    */
-  static void AddIpv4Address(Ptr<Node> n1, int ndNum, 
-                             const Ipv4Address& addr1,
-                             const Ipv4Mask& netmask1);
+  static uint32_t AddIpv4Address(Ptr<Node> node,
+                                 uint32_t netDeviceNumber, 
+                                 const Ipv4Address address,
+                                 const Ipv4Mask mask);
 
   /**
    * \param nd1 Node
--- a/src/devices/csma/csma-net-device.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/devices/csma/csma-net-device.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -19,8 +19,6 @@
  * Author: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
  */
 
-#include <iostream>
-#include <cassert>
 #include "ns3/debug.h"
 #include "ns3/queue.h"
 #include "ns3/simulator.h"
@@ -70,7 +68,6 @@
   return m_type;
 }
 
-
 CsmaNetDevice::CsmaNetDevice (Ptr<Node> node)
   : NetDevice (node, Eui48Address::Allocate ()),
     m_bps (DataRate (0xffffffff))
@@ -81,7 +78,7 @@
 }
 
 CsmaNetDevice::CsmaNetDevice (Ptr<Node> node, Eui48Address addr, 
-                                  CsmaEncapsulationMode encapMode) 
+                              CsmaEncapsulationMode encapMode) 
   : NetDevice(node, addr), 
     m_bps (DataRate (0xffffffff))
 {
@@ -92,8 +89,8 @@
 }
 
 CsmaNetDevice::CsmaNetDevice (Ptr<Node> node, Eui48Address addr, 
-                                  CsmaEncapsulationMode encapMode,
-                                  bool sendEnable, bool receiveEnable) 
+                              CsmaEncapsulationMode encapMode,
+                              bool sendEnable, bool receiveEnable) 
   : NetDevice(node, addr), 
     m_bps (DataRate (0xffffffff))
 {
@@ -142,7 +139,7 @@
   m_queue = 0;
 
   EnableBroadcast (Eui48Address ("ff:ff:ff:ff:ff:ff"));
-  EnableMulticast();
+  EnableMulticast (Eui48Address ("01:00:5e:00:00:00"));
 
   SetSendEnable (sendEnable);
   SetReceiveEnable (receiveEnable);
@@ -513,10 +510,11 @@
   EthernetHeader header (false);
   EthernetTrailer trailer;
   Eui48Address broadcast;
+  Eui48Address multicast;
   Eui48Address destination;
   Packet p = packet;
 
-  NS_DEBUG ("CsmaNetDevice::Receive UID is (" << p.GetUid() << ")");
+  NS_DEBUG ("CsmaNetDevice::Receive ():  UID is " << p.GetUid());
 
   // Only receive if send side of net device is enabled
   if (!IsReceiveEnabled())
@@ -535,12 +533,34 @@
   trailer.CheckFcs(p);
   p.RemoveHeader(header);
 
+  NS_DEBUG ("CsmaNetDevice::Receive ():  Pkt destination is " << 
+    header.GetDestination ());
+//
+// An IP host group address is mapped to an Ethernet multicast address
+// by placing the low-order 23-bits of the IP address into the low-order
+// 23 bits of the Ethernet multicast address 01-00-5E-00-00-00 (hex).
+//
+// We are going to receive all packets destined to any multicast address,
+// which means clearing the low-order 23 bits the header destination 
+//
+  Eui48Address mcDest;
+  uint8_t      mcBuf[6];
+
+  header.GetDestination ().CopyTo (mcBuf);
+  mcBuf[3] &= 0x80;
+  mcBuf[4] = 0;
+  mcBuf[5] = 0;
+  mcDest.CopyFrom (mcBuf);
+
+  multicast = Eui48Address::ConvertFrom (GetMulticast ());
   broadcast = Eui48Address::ConvertFrom (GetBroadcast ());
   destination = Eui48Address::ConvertFrom (GetAddress ());
-  if ((header.GetDestination() != broadcast) &&
-      (header.GetDestination() != destination))
+
+  if ((header.GetDestination () != broadcast) &&
+      (mcDest != multicast) &&
+      (header.GetDestination () != destination))
     {
-      // not for us.
+      NS_DEBUG ("CsmaNetDevice::Receive ():  Dropping pkt ");
       m_dropTrace (p);
       return;
     }
@@ -572,6 +592,61 @@
   return;
 }
 
+Address
+CsmaNetDevice::MakeMulticastAddress(Ipv4Address multicastGroup) const
+{
+  NS_DEBUG ("CsmaNetDevice::MakeMulticastAddress (" << multicastGroup <<
+    ")");
+//
+// First, get the generic multicast address.
+//
+  Address hardwareDestination = GetMulticast ();
+
+  NS_DEBUG ("CsmaNetDevice::MakeMulticastAddress (): "
+    "Device multicast address: " << hardwareDestination);
+//
+// It's our address, and we know we're playing with an EUI-48 address here
+// primarily since we know that by construction, but also since the parameter
+// is an Ipv4Address.
+//
+  Eui48Address etherAddr = Eui48Address::ConvertFrom (hardwareDestination);
+//
+// We now have the multicast address in an abstract 48-bit container.  We 
+// need to pull it out so we can play with it.  When we're done, we have the 
+// high order bits in etherBuffer[0], etc.
+//
+  uint8_t etherBuffer[6];
+  etherAddr.CopyTo (etherBuffer);
+//
+// Now we need to pull the raw bits out of the Ipv4 destination address.
+//
+  uint8_t ipBuffer[4];
+  multicastGroup.Serialize (ipBuffer);
+//
+// RFC 1112 says that an Ipv4 host group address is mapped to an EUI-48
+// multicast address by placing the low-order 23-bits of the IP address into 
+// the low-order 23 bits of the Ethernet multicast address 
+// 01-00-5E-00-00-00 (hex). 
+//
+  etherBuffer[3] |= ipBuffer[1] & 0x7f;
+  etherBuffer[4] = ipBuffer[2];
+  etherBuffer[5] = ipBuffer[3];
+//
+// Now, etherBuffer has the desired ethernet multicast address.  We have to
+// suck these bits back into the Eui48Address,
+//
+  etherAddr.CopyFrom (etherBuffer);
+//
+// Implicit conversion (operator Address ()) is defined for Eui48Address, so
+// use it by just returning the EUI-48 address which is automagically converted
+// to an Address.
+//
+  NS_DEBUG ("CsmaNetDevice::MakeMulticastAddress (): "
+    "multicast address is " << etherAddr);
+
+  return etherAddr;
+}
+
 Ptr<Queue>
 CsmaNetDevice::GetQueue(void) const 
 { 
--- a/src/devices/csma/csma-net-device.h	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/devices/csma/csma-net-device.h	Wed Sep 12 18:06:09 2007 +0100
@@ -205,6 +205,37 @@
    */
   void Receive (const Packet& p);
 
+  /**
+   * @brief Make and return a MAC multicast address using the provided
+   *        multicast group
+   *
+   * RFC 1112 says that an Ipv4 host group address is mapped to an Ethernet 
+   * multicast address by placing the low-order 23-bits of the IP address into 
+   * the low-order 23 bits of the Ethernet multicast address 
+   * 01-00-5E-00-00-00 (hex).
+   *
+   * This method performs the multicast address creation function appropriate
+   * to an EUI-48-based CSMA device.  This MAC address is encapsulated in an
+   *  abstract Address to avoid dependencies on the exact address format.
+   *
+   * A default imlementation of MakeMulticastAddress is provided, but this
+   * method simply NS_ASSERTS.  In the case of net devices that do not support
+   * multicast, clients are expected to test NetDevice::IsMulticast and avoid
+   * attempting to map multicast packets.  Subclasses of NetDevice that do
+   * support multicasting are expected to override this method and provide an
+   * implementation appropriate to the particular device.
+   *
+   * @param multicastGroup The IP address for the multicast group destination
+   * of the packet.
+   * @return The MAC multicast Address used to send packets to the provided
+   * multicast group.
+   *
+   * @see Ipv4Address
+   * @see Eui48Address
+   * @see Address
+   */
+  Address MakeMulticastAddress (Ipv4Address multicastGroup) const;
+
   bool IsSendEnabled (void);
   bool IsReceiveEnabled (void);
 
--- a/src/devices/point-to-point/point-to-point-net-device.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/devices/point-to-point/point-to-point-net-device.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -20,8 +20,6 @@
  * Revised: George Riley <riley@ece.gatech.edu>
  */
 
-#include <iostream>
-#include <cassert>
 #include "ns3/debug.h"
 #include "ns3/queue.h"
 #include "ns3/simulator.h"
@@ -73,11 +71,14 @@
 {
   NS_DEBUG ("PointToPointNetDevice::PointToPointNetDevice (" << node << ")");
 
-  // BUGBUG FIXME
-  //
-  // You _must_ support broadcast to get any sort of packet from the ARP layer.
+// BUGBUG FIXME
+//
+// You _must_ support broadcast to get any sort of packet from the ARP layer.
   EnableBroadcast (Eui48Address ("ff:ff:ff:ff:ff:ff"));
-  EnableMulticast();
+//
+// We want to allow multicast packets to flow across this link
+//
+  EnableMulticast (Eui48Address ("01:00:5e:00:00:00"));
   EnablePointToPoint();
 }
 
@@ -218,6 +219,8 @@
   m_bps = m_channel->GetDataRate ();
   // GFR Comment.  Below is definitely wrong.  Interframe gap
   // is unrelated to channel delay.
+  // -- unlesss you want to introduce a default gap which is there to avoid
+  // parts of multiple packets flowing on the "wire" at the same time.
   //m_tInterframeGap = m_channel->GetDelay ();
 
   /* 
--- a/src/internet-node/arp-ipv4-interface.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/internet-node/arp-ipv4-interface.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -31,18 +31,26 @@
 #include "ipv4-l3-protocol.h"
 #include "arp-l3-protocol.h"
 
+NS_DEBUG_COMPONENT_DEFINE ("ArpIpv4Interface");
+
 namespace ns3 {
 
 ArpIpv4Interface::ArpIpv4Interface (Ptr<Node> node, Ptr<NetDevice> device)
   : Ipv4Interface (device),
     m_node (node)
-{}
+{
+  NS_DEBUG ("ArpIpv4Interface::ArpIpv4Interface ()");
+}
+
 ArpIpv4Interface::~ArpIpv4Interface ()
-{}
+{
+  NS_DEBUG ("ArpIpv4Interface::~ArpIpv4Interface ()");
+}
 
 Ptr<TraceResolver>
 ArpIpv4Interface::GetTraceResolver (void) const
 {
+  NS_DEBUG ("ArpIpv4Interface::DoCreateTraceResolver ()");
   Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
   if (GetDevice () != 0)
     {
@@ -55,32 +63,52 @@
 void 
 ArpIpv4Interface::SendTo (Packet p, Ipv4Address dest)
 {
+  NS_DEBUG ("ArpIpv4Interface::SendTo (" << &p << ", " << dest << ")");
+
   NS_ASSERT (GetDevice () != 0);
   if (GetDevice ()->NeedsArp ())
     {
-      Ptr<ArpL3Protocol> arp = m_node->QueryInterface<ArpL3Protocol> (ArpL3Protocol::iid);
+      NS_DEBUG ("ArpIpv4Interface::SendTo (): Needs ARP");
+      Ptr<ArpL3Protocol> arp = 
+        m_node->QueryInterface<ArpL3Protocol> (ArpL3Protocol::iid);
       Address hardwareDestination;
       bool found;
       
       if (dest.IsBroadcast () || 
           dest.IsSubnetDirectedBroadcast (GetNetworkMask ()) )
         {
+          NS_DEBUG ("ArpIpv4Interface::SendTo (): IsBroadcast");
           hardwareDestination = GetDevice ()->GetBroadcast ();
           found = true;
         }
+      else if (dest.IsMulticast ())
+        {
+          NS_DEBUG ("ArpIpv4Interface::SendTo (): IsMulticast");
+          NS_ASSERT_MSG(GetDevice ()->IsMulticast (),
+            "ArpIpv4Interface::SendTo (): Sending multicast packet over "
+            "non-multicast device");
+
+          hardwareDestination = GetDevice ()->MakeMulticastAddress(dest);
+          found = true;
+        }
       else
         {
+          NS_DEBUG ("ArpIpv4Interface::SendTo (): ARP Lookup");
           found = arp->Lookup (p, dest, GetDevice (), &hardwareDestination);
         }
 
       if (found)
         {
-          GetDevice ()->Send (p, hardwareDestination, Ipv4L3Protocol::PROT_NUMBER);
+          NS_DEBUG ("ArpIpv4Interface::SendTo (): Address Resolved.  Send.");
+          GetDevice ()->Send (p, hardwareDestination, 
+            Ipv4L3Protocol::PROT_NUMBER);
         }
     }
   else
     {
-      GetDevice ()->Send (p, GetDevice ()->GetBroadcast (), Ipv4L3Protocol::PROT_NUMBER);
+      NS_DEBUG ("ArpIpv4Interface::SendTo (): Doesn't need ARP");
+      GetDevice ()->Send (p, GetDevice ()->GetBroadcast (), 
+        Ipv4L3Protocol::PROT_NUMBER);
     }
 }
 
--- a/src/internet-node/arp-ipv4-interface.h	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/internet-node/arp-ipv4-interface.h	Wed Sep 12 18:06:09 2007 +0100
@@ -24,6 +24,7 @@
 
 #include "ipv4-interface.h"
 #include "ns3/ptr.h"
+#include "ns3/eui48-address.h"
 
 namespace ns3 {
 
--- a/src/internet-node/ipv4-impl.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/internet-node/ipv4-impl.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -95,16 +95,72 @@
 {
   return m_ipv4->RemoveRoute (i);
 }
+
+void
+Ipv4Impl::AddMulticastRoute (Ipv4Address origin,
+                             Ipv4Address group,
+                             uint32_t inputInterface,
+                             std::vector<uint32_t> outputInterfaces)
+{
+  m_ipv4->AddMulticastRoute (origin, group, inputInterface, outputInterfaces);
+}
+
+void
+Ipv4Impl::SetDefaultMulticastRoute (uint32_t outputInterface)
+{
+  m_ipv4->SetDefaultMulticastRoute (outputInterface);
+}
+
+uint32_t 
+Ipv4Impl::GetNMulticastRoutes (void) const
+{
+  return m_ipv4->GetNMulticastRoutes ();
+}
+
+Ipv4MulticastRoute 
+Ipv4Impl::GetMulticastRoute (uint32_t i) const
+{
+  return *m_ipv4->GetMulticastRoute (i);
+}
+
+void
+Ipv4Impl::RemoveMulticastRoute (Ipv4Address origin,
+                                Ipv4Address group,
+                                uint32_t inputInterface)
+{
+  m_ipv4->RemoveMulticastRoute (origin, group, inputInterface);
+}
+
+void 
+Ipv4Impl::RemoveMulticastRoute (uint32_t i)
+{
+  return m_ipv4->RemoveMulticastRoute (i);
+}
+
 uint32_t 
 Ipv4Impl::AddInterface (Ptr<NetDevice> device)
 {
   return m_ipv4->AddInterface (device);
 }
+
 uint32_t 
 Ipv4Impl::GetNInterfaces (void)
 {
   return m_ipv4->GetNInterfaces ();
 }
+
+uint32_t 
+Ipv4Impl::FindInterfaceForAddr (Ipv4Address addr) const
+{
+  return m_ipv4->FindInterfaceForAddr (addr);
+}
+
+uint32_t 
+Ipv4Impl::FindInterfaceForAddr (Ipv4Address addr, Ipv4Mask mask) const
+{
+  return m_ipv4->FindInterfaceForAddr (addr, mask);
+}
+
 Ptr<NetDevice>
 Ipv4Impl::GetNetDevice (uint32_t i)
 {
@@ -112,6 +168,18 @@
 }
 
 void 
+Ipv4Impl::JoinMulticastGroup (Ipv4Address origin, Ipv4Address group)
+{
+  m_ipv4->JoinMulticastGroup(origin, group);
+}
+
+void
+Ipv4Impl::LeaveMulticastGroup (Ipv4Address origin, Ipv4Address group)
+{
+  m_ipv4->LeaveMulticastGroup(origin, group);
+}
+
+void 
 Ipv4Impl::SetAddress (uint32_t i, Ipv4Address address)
 {
   m_ipv4->SetAddress (i, address);
@@ -126,11 +194,39 @@
 {
   return m_ipv4->GetNetworkMask (i);
 }
+
 Ipv4Address 
 Ipv4Impl::GetAddress (uint32_t i) const
 {
   return m_ipv4->GetAddress (i);
 }
+
+bool
+Ipv4Impl::GetIfIndexForDestination (Ipv4Address dest, uint32_t &ifIndex) const
+{
+  return m_ipv4->GetIfIndexForDestination (dest, ifIndex);
+}
+
+Ipv4Address 
+Ipv4Impl::GetSourceAddress (Ipv4Address destination) const
+{
+  uint32_t ifIndex = 0xffffffff;
+
+  bool result = m_ipv4->GetIfIndexForDestination (destination, ifIndex);
+
+  if (result)
+    {
+      return m_ipv4->GetAddress (ifIndex);
+    }
+  else
+    {
+//
+// If we can't find any address, just leave it 0.0.0.0
+//
+      return Ipv4Address::GetAny ();
+    }
+}
+
 uint16_t 
 Ipv4Impl::GetMtu (uint32_t i) const
 {
--- a/src/internet-node/ipv4-impl.h	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/internet-node/ipv4-impl.h	Wed Sep 12 18:06:09 2007 +0100
@@ -55,14 +55,43 @@
   virtual uint32_t GetNRoutes (void);
   virtual Ipv4Route GetRoute (uint32_t i);
   virtual void RemoveRoute (uint32_t i);
+
+
+  virtual void AddMulticastRoute (Ipv4Address origin,
+                                  Ipv4Address group,
+                                  uint32_t inputInterface,
+                                  std::vector<uint32_t> outputInterfaces);
+
+  virtual void SetDefaultMulticastRoute (uint32_t outputInterface);
+
+  virtual uint32_t GetNMulticastRoutes (void) const;
+  virtual Ipv4MulticastRoute GetMulticastRoute (uint32_t i) const;
+
+  virtual void RemoveMulticastRoute (Ipv4Address origin,
+                                     Ipv4Address group,
+                                     uint32_t inputInterface);
+  virtual void RemoveMulticastRoute (uint32_t i);
+
   virtual uint32_t AddInterface (Ptr<NetDevice> device);
   virtual uint32_t GetNInterfaces (void);  
+
+  virtual uint32_t FindInterfaceForAddr (Ipv4Address addr) const;
+  virtual uint32_t FindInterfaceForAddr (Ipv4Address addr, 
+    Ipv4Mask mask) const;
+
   virtual Ptr<NetDevice> GetNetDevice(uint32_t i);
 
+  virtual void JoinMulticastGroup (Ipv4Address origin, Ipv4Address group);
+  virtual void LeaveMulticastGroup (Ipv4Address origin, Ipv4Address group);
+
   virtual void SetAddress (uint32_t i, Ipv4Address address);
   virtual void SetNetworkMask (uint32_t i, Ipv4Mask mask);
   virtual Ipv4Mask GetNetworkMask (uint32_t t) const;
   virtual Ipv4Address GetAddress (uint32_t i) const;
+  virtual Ipv4Address GetSourceAddress (Ipv4Address destination) const;
+  virtual bool GetIfIndexForDestination (Ipv4Address dest, 
+    uint32_t &ifIndex) const;
+
   virtual uint16_t GetMtu (uint32_t i) const;
   virtual bool IsUp (uint32_t i) const;
   virtual void SetUp (uint32_t i);
--- a/src/internet-node/ipv4-interface.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/internet-node/ipv4-interface.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -23,6 +23,9 @@
 #include "ns3/ipv4-address.h"
 #include "ns3/net-device.h"
 #include "ns3/trace-resolver.h"
+#include "ns3/debug.h"
+
+NS_DEBUG_COMPONENT_DEFINE ("Ipv4Interface");
 
 namespace ns3 {
 
@@ -35,10 +38,14 @@
 Ipv4Interface::Ipv4Interface (Ptr<NetDevice> nd) 
   : m_netdevice (nd), 
     m_ifup(false)
-{}
+{
+  NS_DEBUG ("Ipv4Interface::Ipv4Interface (" << &nd << ")");
+}
 
 Ipv4Interface::~Ipv4Interface ()
-{}
+{
+  NS_DEBUG ("Ipv4Interface::~Ipv4Interface ()");
+}
 
 void
 Ipv4Interface::DoDispose (void)
@@ -50,42 +57,53 @@
 Ptr<NetDevice>
 Ipv4Interface::GetDevice (void) const
 {
+  NS_DEBUG ("Ipv4Interface::GetDevice ()");
   return m_netdevice;
 }
 
 void 
 Ipv4Interface::SetAddress (Ipv4Address a)
 {
+  NS_DEBUG ("Ipv4Interface::SetAddress (" << a << ")");
   m_address = a;
 }
+
 void 
 Ipv4Interface::SetNetworkMask (Ipv4Mask mask)
 {
+  NS_DEBUG ("Ipv4Interface::SetMask (" << mask << ")");
   m_netmask = mask;
 }
 
 Ipv4Address
 Ipv4Interface::GetBroadcast (void) const
 {
+  NS_DEBUG ("Ipv4Interface::GetBroadcast ()");
+
   uint32_t mask = m_netmask.GetHostOrder ();
   uint32_t address = m_address.GetHostOrder ();
   Ipv4Address broadcast = Ipv4Address (address | (~mask));
   return broadcast;
 }
+
 Ipv4Mask 
 Ipv4Interface::GetNetworkMask (void) const
 {
+  NS_DEBUG ("Ipv4Interface::GetNetworkMask ()");
   return m_netmask;
 }
+
 Ipv4Address 
 Ipv4Interface::GetAddress (void) const
 {
+  NS_DEBUG ("Ipv4Interface::Address ()");
   return m_address;
 }
 
 uint16_t 
 Ipv4Interface::GetMtu (void) const
 {
+  NS_DEBUG ("Ipv4Interface::GetMtu ()");
   if (m_netdevice == 0)
     {
       uint32_t mtu = (1<<16) - 1;
@@ -94,32 +112,36 @@
   return m_netdevice->GetMtu ();
 }
 
-  /**
-   * These are IP interface states and may be distinct from 
-   * NetDevice states, such as found in real implementations
-   * (where the device may be down but IP interface state is still up).
-   */
+/**
+ * These are IP interface states and may be distinct from 
+ * NetDevice states, such as found in real implementations
+ * (where the device may be down but IP interface state is still up).
+ */
 bool 
 Ipv4Interface::IsUp (void) const
 {
+  NS_DEBUG ("Ipv4Interface::IsUp ()");
   return m_ifup;
 }
 
 bool 
 Ipv4Interface::IsDown (void) const
 {
+  NS_DEBUG ("Ipv4Interface::IsDown ()");
   return !m_ifup;
 }
 
 void 
 Ipv4Interface::SetUp (void)
 {
+  NS_DEBUG ("Ipv4Interface::SetUp ()");
   m_ifup = true;
 }
 
 void 
 Ipv4Interface::SetDown (void)
 {
+  NS_DEBUG ("Ipv4Interface::SetDown ()");
   m_ifup = false;
 }
 
@@ -127,7 +149,10 @@
 void 
 Ipv4Interface::Send(Packet p, Ipv4Address dest)
 {
+  NS_DEBUG ("Ipv4Interface::Send ()");
+
   if (IsUp()) {
+    NS_DEBUG ("Ipv4Interface::Send (): SendTo ()");
     SendTo(p, dest);
   }
 }
--- a/src/internet-node/ipv4-l3-protocol.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/internet-node/ipv4-l3-protocol.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -129,17 +129,24 @@
     m_identification (0),
     m_node (node)
 {
+  NS_DEBUG("Ipv4L3Protocol::Ipv4L3Protocol ()");
+
   SetInterfaceId (Ipv4L3Protocol::iid);
   m_staticRouting = Create<Ipv4StaticRouting> ();
   AddRoutingProtocol (m_staticRouting, 0);
   SetupLoopback ();
 }
+
 Ipv4L3Protocol::~Ipv4L3Protocol ()
-{}
+{
+  NS_DEBUG("Ipv4L3Protocol::~Ipv4L3Protocol ()");
+}
 
 void 
 Ipv4L3Protocol::DoDispose (void)
 {
+  NS_DEBUG("Ipv4L3Protocol::DoDispose ()");
+
   m_interfaces.clear ();
   m_node = 0;
   m_staticRouting->Dispose ();
@@ -150,6 +157,8 @@
 void
 Ipv4L3Protocol::SetupLoopback (void)
 {
+  NS_DEBUG("Ipv4L3Protocol::SetupLoopback ()");
+
   Ptr<Ipv4LoopbackInterface> interface = Create<Ipv4LoopbackInterface> (m_node);
   interface->SetAddress (Ipv4Address::GetLoopback ());
   interface->SetNetworkMask (Ipv4Mask::GetLoopback ());
@@ -161,6 +170,8 @@
 Ptr<TraceResolver>
 Ipv4L3Protocol::GetTraceResolver (void) const
 {
+  NS_DEBUG("Ipv4L3Protocol::GetTraceResolver ()");
+
   Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
   resolver->AddSource ("tx", 
                        TraceDoc ("send ipv4 packet to outgoing interface",
@@ -185,6 +196,7 @@
 void 
 Ipv4L3Protocol::SetDefaultTtl (uint8_t ttl)
 {
+  NS_DEBUG("Ipv4L3Protocol::SetDefaultTtl ()");
   m_defaultTtl = ttl;
 }
     
@@ -194,20 +206,28 @@
                       Ipv4Address nextHop, 
                       uint32_t interface)
 {
+  NS_DEBUG("Ipv4L3Protocol::AddHostRouteTo (" << dest << ", " << nextHop <<
+    ", " << interface << ")");
   m_staticRouting->AddHostRouteTo (dest, nextHop, interface);
 }
+
 void 
 Ipv4L3Protocol::AddHostRouteTo (Ipv4Address dest, 
 				uint32_t interface)
 {
+  NS_DEBUG("Ipv4L3Protocol::AddHostRouteTo (" << dest << ", " << 
+    interface << ")");
   m_staticRouting->AddHostRouteTo (dest, interface);
 }
+
 void 
 Ipv4L3Protocol::AddNetworkRouteTo (Ipv4Address network, 
 				   Ipv4Mask networkMask, 
 				   Ipv4Address nextHop, 
 				   uint32_t interface)
 {
+  NS_DEBUG("Ipv4L3Protocol::AddNetworkRouteTo (" << network << ", " << 
+    networkMask << ", " << nextHop << ", " << interface << ")");
   m_staticRouting->AddNetworkRouteTo (network, networkMask, nextHop, interface);
 }
 void 
@@ -215,28 +235,81 @@
 				   Ipv4Mask networkMask, 
 				   uint32_t interface)
 {
+  NS_DEBUG("Ipv4L3Protocol::AddNetworkRouteTo (" << network << ", " << 
+    networkMask << ", " << interface << ")");
   m_staticRouting->AddNetworkRouteTo (network, networkMask, interface);
 }
 void 
 Ipv4L3Protocol::SetDefaultRoute (Ipv4Address nextHop, 
 				 uint32_t interface)
 {
+  NS_DEBUG("Ipv4L3Protocol::SetDefaultRoute (" << nextHop << ", " << 
+    interface << ")");
   m_staticRouting->SetDefaultRoute (nextHop, interface);
 }
 
+void
+Ipv4L3Protocol::Lookup (
+  Ipv4Header const &ipHeader,
+  Packet packet,
+  Ipv4RoutingProtocol::RouteReplyCallback routeReply)
+{
+  NS_DEBUG("Ipv4L3Protocol::Lookup (" << &ipHeader << 
+    ", " << &packet << &routeReply << ")");
+
+  Lookup (Ipv4RoutingProtocol::IF_INDEX_ANY, ipHeader, packet, routeReply);
+}
 
 void
-Ipv4L3Protocol::Lookup (Ipv4Header const &ipHeader,
-                        Packet packet,
-                        Ipv4RoutingProtocol::RouteReplyCallback routeReply)
+Ipv4L3Protocol::Lookup (
+  uint32_t ifIndex,
+  Ipv4Header const &ipHeader,
+  Packet packet,
+  Ipv4RoutingProtocol::RouteReplyCallback routeReply)
 {
-  for (Ipv4RoutingProtocolList::const_iterator rprotoIter = m_routingProtocols.begin ();
-       rprotoIter != m_routingProtocols.end (); rprotoIter++)
+  NS_DEBUG("Ipv4L3Protocol::Lookup (" << ifIndex << ", " << &ipHeader << 
+    ", " << &packet << &routeReply << ")");
+
+  for (Ipv4RoutingProtocolList::const_iterator rprotoIter = 
+         m_routingProtocols.begin ();
+       rprotoIter != m_routingProtocols.end (); 
+       rprotoIter++)
     {
-      if ((*rprotoIter).second->RequestRoute (ipHeader, packet, routeReply))
+      NS_DEBUG("Ipv4L3Protocol::Lookup (): Requesting route");
+      if ((*rprotoIter).second->RequestRoute (ifIndex, ipHeader, packet, 
+                                              routeReply))
         return;
     }
-  // No route found
+
+  if (ipHeader.GetDestination ().IsMulticast () && 
+      ifIndex == Ipv4RoutingProtocol::IF_INDEX_ANY)
+    {
+      NS_DEBUG ("Ipv4L3Protocol::Lookup (): "
+        "Multicast destination with local source");
+//
+// We have a multicast packet originating from the current node and were not
+// able to send it using the usual RequestRoute process.  Since the usual
+// process includes trying to use a default multicast route, this means that
+// there was no specific route out of the node found, and there was no default
+// multicast route set.
+//
+// The fallback position is to look for a default unicast route and use that
+// to get the packet off the node if we have one.
+//
+      Ipv4Route *route = m_staticRouting->GetDefaultRoute ();
+
+      if (route)
+        {
+          NS_DEBUG ("Ipv4StaticRouting::Lookup (): "
+            "Local source. Using unicast default route for multicast packet");
+
+          routeReply (true, *route, packet, ipHeader);
+          return;
+        }
+    }
+//
+// No route found
+//
   routeReply (false, Ipv4Route (), packet, ipHeader);
 }
 
@@ -244,6 +317,8 @@
 Ipv4L3Protocol::AddRoutingProtocol (Ptr<Ipv4RoutingProtocol> routingProtocol,
                                     int priority)
 {
+  NS_DEBUG("Ipv4L3Protocol::AddRoutingProtocol (" << &routingProtocol << 
+    ", " << priority << ")");
   m_routingProtocols.push_back
     (std::pair<int, Ptr<Ipv4RoutingProtocol> > (-priority, routingProtocol));
   m_routingProtocols.sort ();
@@ -252,39 +327,99 @@
 uint32_t 
 Ipv4L3Protocol::GetNRoutes (void)
 {
+  NS_DEBUG("Ipv4L3Protocol::GetNRoutes ()");
   return m_staticRouting->GetNRoutes ();
 }
 
 Ipv4Route *
 Ipv4L3Protocol::GetRoute (uint32_t index)
 {
+  NS_DEBUG("Ipv4L3Protocol::GetRoute ()");
   return m_staticRouting->GetRoute (index);
 }
 
 void 
 Ipv4L3Protocol::RemoveRoute (uint32_t index)
 {
+  NS_DEBUG("Ipv4L3Protocol::RemoveRoute (" << index << ")");
   m_staticRouting->RemoveRoute (index);
 }
 
+void 
+Ipv4L3Protocol::AddMulticastRoute (Ipv4Address origin,
+                                   Ipv4Address group,
+                                   uint32_t inputInterface,
+                                   std::vector<uint32_t> outputInterfaces)
+{
+  NS_DEBUG("Ipv4L3Protocol::AddMulticastRoute (" << origin << ", " <<
+    group << ", " << inputInterface << ", " << &outputInterfaces << ")");
+
+  m_staticRouting->AddMulticastRoute (origin, group, inputInterface,
+    outputInterfaces);
+}
+
+void 
+Ipv4L3Protocol::SetDefaultMulticastRoute (uint32_t outputInterface)
+{
+  NS_DEBUG("Ipv4L3Protocol::SetDefaultMulticastRoute (" << outputInterface <<
+    ")");
+
+  m_staticRouting->SetDefaultMulticastRoute (outputInterface);
+}
+
+uint32_t 
+Ipv4L3Protocol::GetNMulticastRoutes (void) const
+{
+  NS_DEBUG("Ipv4L3Protocol::GetNMulticastRoutes ()");
+  return m_staticRouting->GetNMulticastRoutes ();
+}
+
+Ipv4MulticastRoute *
+Ipv4L3Protocol::GetMulticastRoute (uint32_t index) const
+{
+  NS_DEBUG("Ipv4L3Protocol::GetMulticastRoute (" << index << ")");
+  return m_staticRouting->GetMulticastRoute (index);
+}
+
+void 
+Ipv4L3Protocol::RemoveMulticastRoute (Ipv4Address origin,
+                                       Ipv4Address group,
+                                       uint32_t inputInterface)
+{
+  NS_DEBUG("Ipv4L3Protocol::RemoveMulticastRoute (" << origin << ", " <<
+    group << ", " << inputInterface << ")");
+  m_staticRouting->RemoveMulticastRoute (origin, group, inputInterface);
+}
+
+void 
+Ipv4L3Protocol::RemoveMulticastRoute (uint32_t index)
+{
+  NS_DEBUG("Ipv4L3Protocol::RemoveMulticastRoute (" << index << ")");
+  m_staticRouting->RemoveMulticastRoute (index);
+}
 
 uint32_t 
 Ipv4L3Protocol::AddInterface (Ptr<NetDevice> device)
 {
+  NS_DEBUG("Ipv4L3Protocol::AddInterface (" << &device << ")");
   Ptr<Ipv4Interface> interface = Create<ArpIpv4Interface> (m_node, device);
   return AddIpv4Interface (interface);
 }
+
 uint32_t 
 Ipv4L3Protocol::AddIpv4Interface (Ptr<Ipv4Interface>interface)
 {
+  NS_DEBUG("Ipv4L3Protocol::AddIpv4Interface (" << interface << ")");
   uint32_t index = m_nInterfaces;
   m_interfaces.push_back (interface);
   m_nInterfaces++;
   return index;
 }
+
 Ptr<Ipv4Interface>
 Ipv4L3Protocol::GetInterface (uint32_t index) const
 {
+  NS_DEBUG("Ipv4L3Protocol::GetInterface (" << index << ")");
   uint32_t tmp = 0;
   for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); i++)
     {
@@ -296,15 +431,61 @@
     }
   return 0;
 }
+
 uint32_t 
 Ipv4L3Protocol::GetNInterfaces (void) const
 {
+  NS_DEBUG("Ipv4L3Protocol::GetNInterface ()");
   return m_nInterfaces;
 }
 
+uint32_t 
+Ipv4L3Protocol::FindInterfaceForAddr (Ipv4Address addr) const
+{
+  NS_DEBUG("Ipv4L3Protocol::FindInterfaceForAddr (" << addr << ")");
+
+  uint32_t ifIndex = 0;
+  for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); 
+       i != m_interfaces.end (); 
+       i++, ifIndex++)
+    {
+      if ((*i)->GetAddress () == addr)
+        {
+          return ifIndex;
+        }
+    }
+
+  NS_ASSERT_MSG(false, "Ipv4L3Protocol::FindInterfaceForAddr (): "
+    "Interface not found for IP address");
+  return 0;
+}
+
+uint32_t 
+Ipv4L3Protocol::FindInterfaceForAddr (Ipv4Address addr, Ipv4Mask mask) const
+{
+  NS_DEBUG("Ipv4L3Protocol::FindInterfaceForAddr (" << addr << ", " << 
+    mask << ")");
+
+  uint32_t ifIndex = 0;
+  for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); 
+       i != m_interfaces.end (); 
+       i++, ifIndex++)
+    {
+      if ((*i)->GetAddress ().CombineMask (mask) == addr.CombineMask (mask))
+        {
+          return ifIndex;
+        }
+    }
+
+  NS_ASSERT_MSG(false, "Ipv4L3Protocol::FindInterfaceForAddr (): "
+    "Interface not found for masked IP address");
+  return 0;
+}
+
 Ptr<Ipv4Interface>
 Ipv4L3Protocol::FindInterfaceForDevice (Ptr<const NetDevice> device)
 {
+  NS_DEBUG("Ipv4L3Protocol::FindInterfaceForDevice (" << &device << ")");
   for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); i++)
     {
       if ((*i)->GetDevice () == device)
@@ -318,8 +499,15 @@
 void 
 Ipv4L3Protocol::Receive( Ptr<NetDevice> device, const Packet& p, uint16_t protocol, const Address &from)
 {
+  NS_DEBUG("Ipv4L3Protocol::Receive (" << &device << ", " << &p << ", " <<
+    protocol << ", " << from << ")");
+
+  NS_DEBUG("Ipv4L3Protocol::Receive (): Packet from " << from);
+
   uint32_t index = 0;
-  for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); i++)
+  for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); 
+       i != m_interfaces.end (); 
+       i++)
     {
       if ((*i)->GetDevice () == device)
         {
@@ -337,7 +525,7 @@
       return;
     }
 
-  if (Forwarding (packet, ipHeader, device)) 
+  if (Forwarding (index, packet, ipHeader, device)) 
     {
       return;
     }
@@ -352,6 +540,9 @@
             Ipv4Address destination,
             uint8_t protocol)
 {
+  NS_DEBUG("Ipv4L3Protocol::Send (" << &packet << ", " << source << ", " <<
+    ", " << destination << ", " << protocol << ")");
+
   Ipv4Header ipHeader;
 
   ipHeader.SetSource (source);
@@ -400,36 +591,54 @@
                              Packet packet,
                              Ipv4Header const &ipHeader)
 {
+  NS_DEBUG("Ipv4L3Protocol::SendRealOut (" << found << ", " << &route << 
+    ", " << &packet << &ipHeader << ")");
+
   if (!found)
     {
-      NS_DEBUG ("no route to host. drop.");
+      NS_DEBUG ("Ipv4L3Protocol::SendRealOut (): No route to host.  Drop.");
       m_dropTrace (packet);
       return;
     }
+
+  NS_DEBUG ("Ipv4L3Protocol::SendRealOut (): Send via interface " <<
+        route.GetInterface ());
+
   packet.AddHeader (ipHeader);
   Ptr<Ipv4Interface> outInterface = GetInterface (route.GetInterface ());
   NS_ASSERT (packet.GetSize () <= outInterface->GetMtu ());
   m_txTrace (packet, route.GetInterface ());
   if (route.IsGateway ()) 
     {
+      NS_DEBUG ("Ipv4L3Protocol::SendRealOut (): Send to gateway " <<
+        route.GetGateway ());
       outInterface->Send (packet, route.GetGateway ());
     } 
   else 
     {
+      NS_DEBUG ("Ipv4L3Protocol::SendRealOut (): Send to destination " <<
+        ipHeader.GetDestination ());
       outInterface->Send (packet, ipHeader.GetDestination ());
     }
 }
 
+bool
+Ipv4L3Protocol::Forwarding (
+  uint32_t ifIndex, 
+  Packet const &packet, 
+  Ipv4Header &ipHeader, 
+  Ptr<NetDevice> device)
+{
+  NS_DEBUG("Ipv4L3Protocol::Forwarding (" << ifIndex << ", " << &packet << 
+    ", " << &ipHeader << ", " << device << ")");
 
-bool
-Ipv4L3Protocol::Forwarding (Packet const &packet, Ipv4Header &ipHeader, Ptr<NetDevice> device)
-{
   for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin ();
        i != m_interfaces.end (); i++) 
     {
       if ((*i)->GetAddress ().IsEqual (ipHeader.GetDestination ())) 
         {
-          NS_DEBUG ("for me 1");
+          NS_DEBUG("Ipv4L3Protocol::Forwarding (): "
+            "For me (destination match)");
           return false;
         }
     }
@@ -442,7 +651,8 @@
 	{
 	  if (ipHeader.GetDestination ().IsEqual (interface->GetBroadcast ())) 
 	    {
-	      NS_DEBUG ("for me 2");
+              NS_DEBUG("Ipv4L3Protocol::Forwarding (): "
+                "For me (interface broadcast address)");
 	      return false;
 	    }
 	  break;
@@ -451,78 +661,213 @@
       
   if (ipHeader.GetDestination ().IsBroadcast ()) 
     {
-      NS_DEBUG ("for me 3");
+      NS_DEBUG("Ipv4L3Protocol::Forwarding (): "
+        "For me (Ipv4Addr broadcast address)");
       return false;
     }
+
   if (ipHeader.GetDestination ().IsEqual (Ipv4Address::GetAny ())) 
     {
-      NS_DEBUG ("for me 4");
+      NS_DEBUG("Ipv4L3Protocol::Forwarding (): "
+        "For me (Ipv4Addr any address)");
       return false;
     }
+
   if (ipHeader.GetTtl () == 1) 
     {
       // Should send ttl expired here
       // XXX
-      NS_DEBUG ("not for me -- ttl expired. drop.");
+      NS_DEBUG("Ipv4L3Protocol::Forwarding (): "
+        "Not for me (TTL expired).  Drop");
       m_dropTrace (packet);
       return true;
     }
   ipHeader.SetTtl (ipHeader.GetTtl () - 1);
 
-  NS_DEBUG ("not for me -- forwarding.");
-  Lookup (ipHeader, packet,
+  NS_DEBUG("Ipv4L3Protocol::Forwarding (): Forwarding packet.");
+  Lookup (ifIndex, ipHeader, packet,
           MakeCallback (&Ipv4L3Protocol::SendRealOut, this));
+//
+// If this is a to a multicast address and this node is a member of the 
+// indicated group we need to return false so the multicast is forwarded up.
+// Note that we may have just forwarded this packet too.
+//
+  for (Ipv4MulticastGroupList::const_iterator i = m_multicastGroups.begin ();
+       i != m_multicastGroups.end (); i++) 
+    {
+      if ((*i).first.IsEqual (ipHeader.GetSource ()) &&
+          (*i).second.IsEqual (ipHeader.GetDestination ()))
+        {
+          NS_DEBUG("Ipv4L3Protocol::Forwarding (): "
+            "For me (Joined multicast group)");
+          return false;
+        }
+    }
+  
+  NS_DEBUG("Ipv4L3Protocol::Forwarding (): Not for me.");
   return true;
 }
 
-
 void
 Ipv4L3Protocol::ForwardUp (Packet p, Ipv4Header const&ip)
 {
+  NS_DEBUG("Ipv4L3Protocol::ForwardUp (" << &p << ", " << &ip << ")");
   Ptr<Ipv4L4Demux> demux = m_node->QueryInterface<Ipv4L4Demux> (Ipv4L4Demux::iid);
   Ptr<Ipv4L4Protocol> protocol = demux->GetProtocol (ip.GetProtocol ());
   protocol->Receive (p, ip.GetSource (), ip.GetDestination ());
 }
 
 void 
+Ipv4L3Protocol::JoinMulticastGroup (Ipv4Address origin, Ipv4Address group)
+{
+  NS_DEBUG("Ipv4L3Protocol::JoinMulticastGroup (" << origin << ", " << 
+    group << ")");
+  m_multicastGroups.push_back(
+    std::pair<Ipv4Address, Ipv4Address> (origin, group));
+}
+
+void
+Ipv4L3Protocol::LeaveMulticastGroup (Ipv4Address origin, Ipv4Address group)
+{
+  NS_DEBUG("Ipv4L3Protocol::LeaveMulticastGroup (" << origin << ", " << 
+    group << ")");
+
+  for (Ipv4MulticastGroupList::iterator i = m_multicastGroups.begin ();
+       i != m_multicastGroups.end (); 
+       i++)
+    {
+      if ((*i).first.IsEqual(origin) && (*i).second.IsEqual(group))
+        {
+          m_multicastGroups.erase (i);
+          return;
+        }
+    }
+}
+
+void 
 Ipv4L3Protocol::SetAddress (uint32_t i, Ipv4Address address)
 {
+  NS_DEBUG("Ipv4L3Protocol::SetAddress (" << i << ", " << address << ")");
   Ptr<Ipv4Interface> interface = GetInterface (i);
   interface->SetAddress (address);
 }
+
 void 
 Ipv4L3Protocol::SetNetworkMask (uint32_t i, Ipv4Mask mask)
 {
+  NS_DEBUG("Ipv4L3Protocol::SetNetworkMask (" << i << ", " << mask << ")");
   Ptr<Ipv4Interface> interface = GetInterface (i);
   interface->SetNetworkMask (mask);
 }
+
 Ipv4Mask 
 Ipv4L3Protocol::GetNetworkMask (uint32_t i) const
 {
+  NS_DEBUG("Ipv4L3Protocol::GetNetworkMask (" << i << ")");
   Ptr<Ipv4Interface> interface = GetInterface (i);
   return interface->GetNetworkMask ();
 }
+
 Ipv4Address 
 Ipv4L3Protocol::GetAddress (uint32_t i) const
 {
+  NS_DEBUG("Ipv4L3Protocol::GetAddress (" << i << ")");
   Ptr<Ipv4Interface> interface = GetInterface (i);
   return interface->GetAddress ();
 }
+
+bool
+Ipv4L3Protocol::GetIfIndexForDestination (
+  Ipv4Address destination, uint32_t& ifIndex) const
+{
+  NS_DEBUG("Ipv4L3Protocol::GetIfIndexForDestination (" << destination << 
+    ", " << &ifIndex << ")");
+//
+// The first thing we do in trying to determine a source address is to 
+// consult the routing protocols.  These will also check for a default route
+// if one has been set.
+//
+  for (Ipv4RoutingProtocolList::const_iterator i = m_routingProtocols.begin ();
+       i != m_routingProtocols.end (); 
+       i++)
+    {
+      NS_DEBUG("Ipv4L3Protocol::Lookup (): Requesting Source Address");
+      uint32_t ifIndexTmp;
+
+      if ((*i).second->RequestIfIndex (destination, ifIndexTmp))
+        {
+          NS_DEBUG("Ipv4L3Protocol::GetIfIndexForDestination (): "
+            "Found ifIndex " << ifIndexTmp);
+          ifIndex = ifIndexTmp;
+          return true;
+        }
+    }
+//
+// If there's no routing table entry telling us what *single* interface will 
+// be used to send a packet to this destination, we'll have to just pick one.  
+// If there's only one interface on this node, a good answer isn't very hard
+// to come up with.  Before jumping to any conclusions, remember that the 
+// zeroth interface is the loopback interface, so what we actually want is
+// a situation where there are exactly two interfaces on the node, in which
+// case interface one is the "single" interface connected to the outside world.
+//
+  if (GetNInterfaces () == 2)
+    {
+      NS_DEBUG("Ipv4L3Protocol::GetIfIndexForDestination (): "
+        "One Interface.  Using interface 1.");
+      ifIndex = 1;
+      return true;
+    }
+//
+// If we fall through to here, we have a node with multiple interfaces and
+// no routes to guide us in determining what interface to choose.  Either
+// no default route was found (for unicast or multicast), or in the case of a
+// multicast, the default route contained multiple outbound interfaces.
+//
+// The fallback position is to just get the unicast default route and use 
+// the outgoing interface specified there.  We don't want to leave the source
+// address unset, so we just assert here.
+//
+// N.B. that in the case of a multicast with a route containing multiple
+// outgoing interfaces, the source address of packets from that node will be
+// set to the IP address of the interface set in the default unicast route.
+// Also, in the case of a broadcast, the same will be true.
+//
+  NS_DEBUG("Ipv4L3Protocol::GetIfIndexForDestination (): "
+    "Using default unicast route");
+  Ipv4Route *route = m_staticRouting->GetDefaultRoute ();
+
+  NS_ASSERT_MSG(route, 
+    "Ipv4L3Protocol::GetIfIndexForDestination (): "
+    "Unable to determine outbound interface.  No default route set");
+
+  ifIndex = route->GetInterface ();
+
+  NS_DEBUG("Ipv4L3Protocol::GetIfIndexForDestination (): "
+    "Default route specifies interface " << ifIndex);
+  return true;
+}
+
 uint16_t 
 Ipv4L3Protocol::GetMtu (uint32_t i) const
 {
+  NS_DEBUG("Ipv4L3Protocol::GetMtu (" << i << ")");
   Ptr<Ipv4Interface> interface = GetInterface (i);
   return interface->GetMtu ();
 }
+
 bool 
 Ipv4L3Protocol::IsUp (uint32_t i) const
 {
+  NS_DEBUG("Ipv4L3Protocol::IsUp (" << i << ")");
   Ptr<Ipv4Interface> interface = GetInterface (i);
   return interface->IsUp ();
 }
+
 void 
 Ipv4L3Protocol::SetUp (uint32_t i)
 {
+  NS_DEBUG("Ipv4L3Protocol::SetUp (" << i << ")");
   Ptr<Ipv4Interface> interface = GetInterface (i);
   interface->SetUp ();
 
@@ -536,9 +881,11 @@
                          interface->GetNetworkMask (), i);
     }
 }
+
 void 
 Ipv4L3Protocol::SetDown (uint32_t ifaceIndex)
 {
+  NS_DEBUG("Ipv4L3Protocol::SetDown (" << ifaceIndex << ")");
   Ptr<Ipv4Interface> interface = GetInterface (ifaceIndex);
   interface->SetDown ();
 
--- a/src/internet-node/ipv4-l3-protocol.h	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/internet-node/ipv4-l3-protocol.h	Wed Sep 12 18:06:09 2007 +0100
@@ -169,15 +169,37 @@
   Ipv4Route *GetRoute (uint32_t i);
   void RemoveRoute (uint32_t i);
 
+  void AddMulticastRoute (Ipv4Address origin,
+                          Ipv4Address group,
+                          uint32_t inputInterface,
+                          std::vector<uint32_t> outputInterfaces);
+
+  void SetDefaultMulticastRoute (uint32_t onputInterface);
+
+  uint32_t GetNMulticastRoutes (void) const;
+  Ipv4MulticastRoute *GetMulticastRoute (uint32_t i) const;
+
+  void RemoveMulticastRoute (Ipv4Address origin,
+                             Ipv4Address group,
+                             uint32_t inputInterface);
+  void RemoveMulticastRoute (uint32_t i);
+
   uint32_t AddInterface (Ptr<NetDevice> device);
   Ptr<Ipv4Interface> GetInterface (uint32_t i) const;
   uint32_t GetNInterfaces (void) const;
 
+  uint32_t FindInterfaceForAddr (Ipv4Address addr) const;
+  uint32_t FindInterfaceForAddr (Ipv4Address addr, Ipv4Mask mask) const;
   
+  void JoinMulticastGroup (Ipv4Address origin, Ipv4Address group);
+  void LeaveMulticastGroup (Ipv4Address origin, Ipv4Address group);
+
   void SetAddress (uint32_t i, Ipv4Address address);
   void SetNetworkMask (uint32_t i, Ipv4Mask mask);
   Ipv4Mask GetNetworkMask (uint32_t t) const;
   Ipv4Address GetAddress (uint32_t i) const;
+  bool GetIfIndexForDestination (Ipv4Address destination, 
+                                 uint32_t& ifIndex) const;
   uint16_t GetMtu (uint32_t i) const;
   bool IsUp (uint32_t i) const;
   void SetUp (uint32_t i);
@@ -192,17 +214,26 @@
   virtual Ptr<TraceResolver> GetTraceResolver (void) const;
 
 private:
+  void Lookup (uint32_t ifIndex,
+               Ipv4Header const &ipHeader,
+               Packet packet,
+               Ipv4RoutingProtocol::RouteReplyCallback routeReply);
 
   void SendRealOut (bool found,
                     Ipv4Route const &route,
                     Packet packet,
                     Ipv4Header const &ipHeader);
-  bool Forwarding (Packet const &packet, Ipv4Header &ipHeader, Ptr<NetDevice> device);
+  bool Forwarding (uint32_t ifIndex, 
+                   Packet const &packet, 
+                   Ipv4Header &ipHeader, 
+                   Ptr<NetDevice> device);
   void ForwardUp (Packet p, Ipv4Header const&ip);
   uint32_t AddIpv4Interface (Ptr<Ipv4Interface> interface);
   void SetupLoopback (void);
 
   typedef std::list<Ptr<Ipv4Interface> > Ipv4InterfaceList;
+  typedef std::list<std::pair<Ipv4Address, Ipv4Address> > 
+    Ipv4MulticastGroupList;
   typedef std::list< std::pair< int, Ptr<Ipv4RoutingProtocol> > > Ipv4RoutingProtocolList;
 
   Ipv4InterfaceList m_interfaces;
@@ -217,6 +248,7 @@
   Ipv4RoutingProtocolList m_routingProtocols;
 
   Ptr<Ipv4StaticRouting> m_staticRouting;
+  Ipv4MulticastGroupList m_multicastGroups;
 };
 
 } // Namespace ns3
--- a/src/internet-node/ipv4-loopback-interface.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/internet-node/ipv4-loopback-interface.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -19,25 +19,41 @@
  * Authors: 
  *  Mathieu Lacage <mathieu.lacage@sophia.inria.fr>,
  */
+
+#include "ns3/debug.h"
 #include "ns3/net-device.h"
 #include "ns3/node.h"
 #include "ns3/eui48-address.h"
 #include "ipv4-loopback-interface.h"
 #include "ipv4-l3-protocol.h"
 
+NS_DEBUG_COMPONENT_DEFINE ("Ipv4LoopbackInterface");
+
 namespace ns3 {
 
 Ipv4LoopbackInterface::Ipv4LoopbackInterface (Ptr<Node> node)
   : Ipv4Interface (0),
     m_node (node)
-{}
+{
+  NS_DEBUG("Ipv4LoopbackInterface::Ipv4LoopbackInterface ()");
+}
+
 Ipv4LoopbackInterface::~Ipv4LoopbackInterface ()
-{}
+{
+  NS_DEBUG("Ipv4LoopbackInterface::~Ipv4LoopbackInterface ()");
+}
+
 void 
 Ipv4LoopbackInterface::SendTo (Packet packet, Ipv4Address dest)
 {
-  Ptr<Ipv4L3Protocol> ipv4 = m_node->QueryInterface<Ipv4L3Protocol> (Ipv4L3Protocol::iid);
-  ipv4->Receive (GetDevice (), packet, Ipv4L3Protocol::PROT_NUMBER, Eui48Address ("ff:ff:ff:ff:ff:ff"));
+  NS_DEBUG("Ipv4LoopbackInterface::SendTo (" << &packet << ", " << 
+    dest << ")");
+
+  Ptr<Ipv4L3Protocol> ipv4 = 
+    m_node->QueryInterface<Ipv4L3Protocol> (Ipv4L3Protocol::iid);
+
+  ipv4->Receive (GetDevice (), packet, Ipv4L3Protocol::PROT_NUMBER, 
+    Eui48Address ("ff:ff:ff:ff:ff:ff"));
 }
 
 }//namespace ns3
--- a/src/internet-node/ipv4-static-routing.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/internet-node/ipv4-static-routing.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -19,22 +19,30 @@
 // Author: George F. Riley<riley@ece.gatech.edu>
 //         Gustavo Carneiro <gjc@inescporto.pt>
 
+#include "ns3/debug.h"
 #include "ipv4-static-routing.h"
 #include "ns3/packet.h"
 
+NS_DEBUG_COMPONENT_DEFINE ("Ipv4StaticRouting");
 
 namespace ns3 {
 
+Ipv4StaticRouting::Ipv4StaticRouting () 
+: m_defaultRoute (0), m_defaultMulticastRoute (0)
+{
+}
 
 void 
 Ipv4StaticRouting::AddHostRouteTo (Ipv4Address dest, 
                                    Ipv4Address nextHop, 
                                    uint32_t interface)
 {
+
   Ipv4Route *route = new Ipv4Route ();
   *route = Ipv4Route::CreateHostRouteTo (dest, nextHop, interface);
   m_hostRoutes.push_back (route);
 }
+
 void 
 Ipv4StaticRouting::AddHostRouteTo (Ipv4Address dest, 
                                    uint32_t interface)
@@ -43,6 +51,7 @@
   *route = Ipv4Route::CreateHostRouteTo (dest, interface);
   m_hostRoutes.push_back (route);
 }
+
 void 
 Ipv4StaticRouting::AddNetworkRouteTo (Ipv4Address network, 
                                       Ipv4Mask networkMask, 
@@ -56,6 +65,7 @@
                                             interface);
   m_networkRoutes.push_back (route);
 }
+
 void 
 Ipv4StaticRouting::AddNetworkRouteTo (Ipv4Address network, 
                                       Ipv4Mask networkMask, 
@@ -67,6 +77,7 @@
                                             interface);
   m_networkRoutes.push_back (route);
 }
+
 void 
 Ipv4StaticRouting::SetDefaultRoute (Ipv4Address nextHop, 
                                     uint32_t interface)
@@ -77,6 +88,168 @@
   m_defaultRoute = route;
 }
 
+void 
+Ipv4StaticRouting::AddMulticastRoute(Ipv4Address origin,
+                                     Ipv4Address group,
+                                     uint32_t inputInterface,
+                                     std::vector<uint32_t> outputInterfaces)
+{
+  Ipv4MulticastRoute *route = new Ipv4MulticastRoute ();
+  *route = Ipv4MulticastRoute::CreateMulticastRoute (origin, group, 
+    inputInterface, outputInterfaces);
+  m_multicastRoutes.push_back (route);
+}
+
+void 
+Ipv4StaticRouting::SetDefaultMulticastRoute(uint32_t outputInterface)
+{
+  Ipv4Address origin = Ipv4Address::GetAny ();
+  Ipv4Address group = Ipv4Address::GetAny ();
+  uint32_t inputInterface = Ipv4RoutingProtocol::IF_INDEX_ANY;
+
+  std::vector<uint32_t> outputInterfaces (1);
+  outputInterfaces[0] = outputInterface;
+  
+  Ipv4MulticastRoute *route = new Ipv4MulticastRoute ();
+  *route = Ipv4MulticastRoute::CreateMulticastRoute (origin, group, 
+    inputInterface, outputInterfaces);
+
+  delete m_defaultMulticastRoute;
+  m_defaultMulticastRoute = route;
+}
+
+uint32_t 
+Ipv4StaticRouting::GetNMulticastRoutes (void) const
+{
+  return m_multicastRoutes.size () + m_defaultMulticastRoute ? 1 : 0;
+}
+
+Ipv4MulticastRoute *
+Ipv4StaticRouting::GetMulticastRoute (uint32_t index) const
+{
+  NS_ASSERT_MSG(index < m_multicastRoutes.size (),
+    "Ipv4StaticRouting::GetMulticastRoute ():  Index out of range");
+//
+// From an external point of view the default route appears to be in slot 0
+// of the routing table.  The implementation, however, puts it in a separate 
+// place.  So, if a client asks for index 0 and we have a default multicast
+// route, we have to return it from that different place 
+// (m_defaultMulticastRoute).
+//
+  if (index == 0 && m_defaultMulticastRoute != 0)
+    {
+      return m_defaultMulticastRoute;
+    }
+//
+// If there is a default multicast route present, a client will just assume
+// that it is in slot zero and there is one "extra" zeroth route in the table.
+// To return the correct indexed entry in our list, we have to decrement the
+// index to take into account the default route not being in the actual list.
+// Since we fell through to here, we've taken care of the case where the
+// index was zero.
+//
+  if (m_defaultMulticastRoute != 0)
+    {
+      NS_ASSERT(index > 0);
+      index--;
+    }
+
+  if (index < m_multicastRoutes.size ())
+    {
+      uint32_t tmp = 0;
+      for (MulticastRoutesCI i = m_multicastRoutes.begin (); 
+           i != m_multicastRoutes.end (); 
+           i++) 
+        {
+          if (tmp  == index)
+            {
+              return *i;
+            }
+          tmp++;
+        }
+    }
+  return 0;
+}
+
+Ipv4MulticastRoute *
+Ipv4StaticRouting::GetDefaultMulticastRoute () const
+{
+  if (m_defaultMulticastRoute != 0)
+    {
+      return m_defaultMulticastRoute;
+    }
+  return 0;
+}
+
+bool
+Ipv4StaticRouting::RemoveMulticastRoute(Ipv4Address origin,
+                                        Ipv4Address group,
+                                        uint32_t inputInterface)
+{
+//
+// This method does not attempt to delete the multicast route.
+// 
+  for (MulticastRoutesI i = m_multicastRoutes.begin (); 
+       i != m_multicastRoutes.end (); 
+       i++) 
+    {
+      Ipv4MulticastRoute *route = *i;
+      if (origin == route->GetOrigin () &&
+          group == route->GetGroup () &&
+          inputInterface == route->GetInputInterface ())
+        {
+          delete *i;
+          m_multicastRoutes.erase (i);
+          return true;
+        }
+    }
+  return false;
+}
+
+void 
+Ipv4StaticRouting::RemoveMulticastRoute(uint32_t index)
+{
+//
+// From an external point of view the default route appears to be in slot 0
+// of the routing table.  The implementation, however, puts it in a separate 
+// place.  So, if a client asks to delete index 0 and we have a default
+// multicast route set, we have to delete it from that different place 
+// (m_defaultMulticastRoute).
+//
+  if (index == 0 && m_defaultMulticastRoute != 0)
+    {
+      delete m_defaultMulticastRoute;
+      m_defaultMulticastRoute = 0;
+    }
+//
+// If there is a default multicast route present, a client will just assume
+// that it is in slot zero and there is one "extra" zeroth route in the table.
+// To return the correct indexed entry in our list, we have to decrement the
+// index to take into account the default route not being in the actual list.
+// Since we fell through to here, we've taken care of the case where the
+// index was zero.
+//
+  if (m_defaultMulticastRoute != 0)
+    {
+      NS_ASSERT(index > 0);
+      index--;
+    }
+
+  uint32_t tmp = 0;
+  for (MulticastRoutesI i = m_multicastRoutes.begin (); 
+       i != m_multicastRoutes.end (); 
+       i++) 
+    {
+      if (tmp  == index)
+        {
+          delete *i;
+          m_multicastRoutes.erase (i);
+          return;
+        }
+      tmp++;
+    }
+}
+
 Ipv4Route *
 Ipv4StaticRouting::LookupStatic (Ipv4Address dest)
 {
@@ -110,6 +283,110 @@
   return 0;
 }
 
+Ipv4MulticastRoute *
+Ipv4StaticRouting::LookupStatic (
+  Ipv4Address origin, 
+  Ipv4Address group,
+  uint32_t    ifIndex)
+{
+//
+// We treat the "any" address (typically 0.0.0.0) as a wildcard in our matching
+// scheme.
+//
+  Ipv4Address wildcard = Ipv4Address::GetAny ();
+
+  for (MulticastRoutesI i = m_multicastRoutes.begin (); 
+       i != m_multicastRoutes.end (); 
+       i++) 
+    {
+      Ipv4MulticastRoute *route = *i;
+//
+// We've been passed an origin address, a multicast group address and an 
+// interface index.  We have to decide if the current route in the list is
+// a match.
+//
+// The first case is the restrictive case where the origin, group and index
+// matches.  This picks up exact routes during forwarded and exact routes from
+// the local node (in which case the ifIndex is a wildcard).
+//
+      if (origin == route->GetOrigin () && group == route->GetGroup ())
+        {
+          if (ifIndex == Ipv4RoutingProtocol::IF_INDEX_ANY || 
+              ifIndex == route->GetInputInterface ())
+            {
+              return *i;
+            }
+        }
+    }
+//
+// If the input interface index is not a wildcard (that means that the packet 
+// did not originally come from this node), we're done.  We don't
+// just happily forward packets we don't really know what to do with.  
+// Multicast storms are not generally considered a good thing.
+//
+  if (ifIndex != Ipv4RoutingProtocol::IF_INDEX_ANY)
+    {
+      return 0;
+    }
+//
+// Now, we're going to get a litle less restricive.  This only applies in the
+// case where the packet in question is coming from the local node.  In order
+// to avoid dependencies on the order in which routes were added, we will 
+// actually walk the list two more times, the first time looking for routes
+// with a single wildcard, and the last time looking for the first route
+// with two wildcards.
+//
+  for (MulticastRoutesI i = m_multicastRoutes.begin (); 
+       i != m_multicastRoutes.end (); 
+       i++) 
+    {
+      Ipv4MulticastRoute *route = *i;
+//
+// Here we will ignore the origin.  We know that a single source address must
+// be picked for a packet, but we may want to send multicast packets out
+// multiple interfaces.  To support this case, a user would need to add
+// a Multicast route with the route's origin set to wildcard.  N.B As a
+// result, packets sourced from a node with multiple interface may have a
+// source IP address different from that of the interface actually used to
+// send the packet.
+//
+      if (route->GetOrigin () == wildcard && group == route->GetGroup ())
+        {
+          return *i;
+        }
+    }
+//
+// Finally we want to allow users to specify a default route that specifies
+// sending all multicast packets out multiple interfaces.  The standard
+// default multicast route is patterned after other systems and limits the 
+// number of outputs to one.  If, however a client manually adds a multicast
+// route with the origin, the multicast group and the input interface index
+// all set to wildcard, she has created a default route with multiple output
+// interfaces.
+//
+  for (MulticastRoutesI i = m_multicastRoutes.begin (); 
+       i != m_multicastRoutes.end (); 
+       i++) 
+    {
+      Ipv4MulticastRoute *route = *i;
+
+      if (route->GetOrigin () == wildcard && route->GetGroup () == wildcard)
+        {
+          return *i;
+        }
+    }
+//
+// We also allow users to specify a typical default multicast route.  This
+// default route is limited to specifying a single output interface.
+//
+  if (m_defaultMulticastRoute != 0) 
+    {
+      return m_defaultMulticastRoute;
+    }
+
+  return 0;
+}
+
 uint32_t 
 Ipv4StaticRouting::GetNRoutes (void)
 {
@@ -122,6 +399,20 @@
   n += m_networkRoutes.size ();
   return n;
 }
+
+Ipv4Route *
+Ipv4StaticRouting::GetDefaultRoute ()
+{
+  if (m_defaultRoute != 0)
+    {
+      return m_defaultRoute;
+    }
+  else
+    {
+      return 0;
+    }
+}
+
 Ipv4Route *
 Ipv4StaticRouting::GetRoute (uint32_t index)
 {
@@ -209,10 +500,52 @@
 }
 
 bool
-Ipv4StaticRouting::RequestRoute (Ipv4Header const &ipHeader,
-                                 Packet packet,
-                                 RouteReplyCallback routeReply)
+Ipv4StaticRouting::RequestRoute (
+  uint32_t ifIndex,
+  Ipv4Header const &ipHeader,
+  Packet packet,
+  RouteReplyCallback routeReply)
 {
+  NS_DEBUG ("Ipv4StaticRouting::RequestRoute (" << &ipHeader << ", " <<
+    &packet << ", " << &routeReply << ")");
+
+  NS_DEBUG ("Ipv4StaticRouting::RequestRoute (): source = " << 
+    ipHeader.GetSource ());
+
+  NS_DEBUG ("Ipv4StaticRouting::RequestRoute (): destination = " << 
+    ipHeader.GetDestination ());
+
+  if (ipHeader.GetDestination ().IsMulticast ())
+    {
+      NS_DEBUG ("Ipv4StaticRouting::RequestRoute (): Multicast destination");
+
+      Ipv4MulticastRoute *mRoute = LookupStatic(ipHeader.GetSource (),
+        ipHeader.GetDestination (), ifIndex);
+
+      if (mRoute)
+        {
+          NS_DEBUG ("Ipv4StaticRouting::RequestRoute (): "
+            "Multicast route found");
+
+          for (uint32_t i = 0; i < mRoute->GetNOutputInterfaces (); ++i)
+            {
+              Packet p = packet;
+              Ipv4Header h = ipHeader;
+              Ipv4Route route = 
+                Ipv4Route::CreateHostRouteTo(h.GetDestination (), 
+                  mRoute->GetOutputInterface(i));
+              NS_DEBUG ("Ipv4StaticRouting::RequestRoute (): "
+                "Send via interface " << mRoute->GetOutputInterface(i));
+              routeReply (true, route, p, h);
+            }
+          return true;
+        }
+      return false; // Let other routing protocols try to handle this
+    }
+//
+// This is a unicast packet.  Check to see if we have a route for it.
+//
+  NS_DEBUG ("Ipv4StaticRouting::RequestRoute (): Unicast destination");
   Ipv4Route *route = LookupStatic (ipHeader.GetDestination ());
   if (route != 0)
     {
@@ -226,6 +559,57 @@
     }
 }
 
+bool
+Ipv4StaticRouting::RequestIfIndex (Ipv4Address destination, uint32_t& ifIndex)
+{
+  NS_DEBUG ("Ipv4StaticRouting::RequestIfIndex (" << destination << ", " <<
+    &ifIndex << ")");
+//
+// First, see if this is a multicast packet we have a route for.  If we
+// have a route, then send the packet down each of the specified interfaces.
+//
+  if (destination.IsMulticast ())
+    {
+      NS_DEBUG ("Ipv4StaticRouting::RequestIfIndex (): Multicast destination");
+
+      Ipv4MulticastRoute *mRoute = LookupStatic(Ipv4Address::GetAny (),
+        destination, Ipv4RoutingProtocol::IF_INDEX_ANY);
+
+      if (mRoute)
+        {
+          NS_DEBUG ("Ipv4StaticRouting::RequestIfIndex (): "
+            "Multicast route found");
+
+          if (mRoute->GetNOutputInterfaces () != 1)
+            {
+              NS_DEBUG ("Ipv4StaticRouting::RequestIfIndex (): "
+                "Route is to multiple interfaces.  Ignoring.");
+              return false;
+            }
+
+          ifIndex = mRoute->GetOutputInterface(0);
+          NS_DEBUG ("Ipv4StaticRouting::RequestIfIndex (): "
+            "Found ifIndex " << ifIndex);
+          return true;
+        }
+      return false; // Let other routing protocols try to handle this
+    }
+//
+// See if this is a unicast packet we have a route for.
+//
+  NS_DEBUG ("Ipv4StaticRouting::RequestIfIndex (): Unicast destination");
+  Ipv4Route *route = LookupStatic (destination);
+  if (route)
+    {
+      ifIndex = route->GetInterface ();
+      return true;
+    }
+  else
+    {
+      return false;
+    }
+}
+
 void
 Ipv4StaticRouting::DoDispose (void)
 {
@@ -246,8 +630,18 @@
       delete m_defaultRoute;
       m_defaultRoute = 0;
     }
+  for (MulticastRoutesI i = m_multicastRoutes.begin (); 
+       i != m_multicastRoutes.end (); 
+       i = m_multicastRoutes.erase (i)) 
+    {
+      delete (*i);
+    }
+  if (m_defaultMulticastRoute != 0)
+    {
+      delete m_defaultMulticastRoute;
+      m_defaultMulticastRoute = 0;
+    }
   Ipv4RoutingProtocol::DoDispose ();
 }
 
-
 }//namespace ns3
--- a/src/internet-node/ipv4-static-routing.h	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/internet-node/ipv4-static-routing.h	Wed Sep 12 18:06:09 2007 +0100
@@ -45,36 +45,441 @@
 class TraceContext;
 
 
+/**
+ * @brief Static routing protocol for IP version 4 stacks.
+ *
+ * In ns-3 we have the concept of a pluggable routing protocol.  Routing
+ * protocols are added to a list maintained by the Ipv4L3Protocol.  Every 
+ * stack gets one routing protocol for free -- the Ipv4StaticRouting routing
+ * protocol is added in the constructor of the Ipv4L3Protocol (this is the 
+ * piece of code that implements the functionality of the IP layer).
+ *
+ * The Ipv4StaticRouting class inherits from the abstract base class 
+ * Ipv4RoutingProtocol that defines the interface methods that a routing 
+ * protocol must support.
+ *
+ * When a packet arrives in the Ipv4L3Protocol for transmission, it comes
+ * either from a local source via Ipv4L3Protocol::Send or from a remote 
+ * source via Ipv4L3Protocol::Forwarding.  In both cases, a function is called
+ * (Ipv4L3Protocol::Lookup) to look up the routing information for the packet.
+ *
+ * The lookup function iterates through the list of routing protocols asking
+ * each to see if it can find a route and send the packet.  A callback is 
+ * provided during each of these calls that should be considered a pre-
+ * packaged send call.  This is done to allow asynchronous calls into 
+ * routing subsystems in order to support on-demand routing, for example.  The
+ * method for requesting this operation is Ipv4StaticRouting::RequestRoute for
+ * the static routing protocol.
+ *
+ * Each routing protocol is also free to implement its own methods for managing
+ * routes which you will find below.  This class manages a set of "static" or
+ * manually configured routes for host, network and multicast routes.
+ *
+ * @see Ipv4RoutingProtocol
+ * @see Ipv4L3Protocol::AddRoutingProtocol
+ * @see Ipv4L3Protocol::Ipv4L3Protocol
+ */
 class Ipv4StaticRouting : public Ipv4RoutingProtocol
 {
+public:
+/**
+ * @brief Construct an empty Ipv4StaticRouting routing protocol,
+ * @internal
+ *
+ * The Ipv4StaticRouting class supports host, network and multicast routes.
+ * This method initializes the lists containing these routes to empty.
+ *
+ * @see Ipv4StaticRouting
+ */
+  Ipv4StaticRouting ();
 
-public:
-  Ipv4StaticRouting () : m_defaultRoute (0) {}
-
-  virtual bool RequestRoute (Ipv4Header const &ipHeader,
+/**
+ * @brief Request that a check for a route bw performed and if a route is found
+ * that the packet be sent on its way using the pre-packaged send callback.
+ *
+ * The source and destination IP addresses for the packet in question are found
+ * in the provided Ipv4Header.  There are two major processing forks depending
+ * on the type of destination address.  
+ *
+ * If the destination address is unicast then the routing table is consulted 
+ * for a route to the destination and if it is found, the routeReply callback
+ * is executed to send the packet (with the found route).
+ * 
+ * If the destination address is a multicast, then the exact processing steps
+ * depend on whether or not the packet has been sourced locally.  This is 
+ * determined by the parameter ifIndex.  This is the interface index over which
+ * this packet was received.  If the packet has not been received over a
+ * network interface, this index will be set to 
+ * Ipv4RoutingProtocol::IF_INDEX_ANY (a very large number).  In that case, 
+ * we want to avoid the requirement that an explicit route out of each node 
+ * must be set, so we don't do anything here.
+ * 
+ * If the packet is a multicast destination and has been received over a 
+ * network interface, a call to this method implies that the packet is being
+ * forwarded.  In that case, there must be an explicit route out of the node.
+ * A multicast route references the source address, the destination address
+ * (the multicast group) and the input interface in order to find a route.
+ * We consult the multicast routing table and, if a route is found, send the
+ * packet out of as many interfaces as required using the provided callback
+ * (think of it as a pre-packaged send call).
+ *
+ * @param ifIndex The network interface index over which the packed was 
+ * received.  If the packet is from a local source, ifIndex will be set to
+ * Ipv4RoutingProtocol::IF_INDEX_ANY.
+ * @param ipHeader the Ipv4Header containing the source and destination IP
+ * addresses for the packet.
+ * @param packet The packet to be sent if a route is found.
+ * @param routeReply A callback that packaged up the call to actually send the
+ * packet.
+ * @return Returns true if a route is found and the packet has been sent,
+ * otherwise returns false indicating that the next routing protocol should
+ * be consulted.  In practice, the static routing protocol is the last chance
+ * protocol.
+ *
+ * @see Ipv4StaticRouting
+ * @see Ipv4RoutingProtocol
+ */
+  virtual bool RequestRoute (uint32_t ifIndex,
+                             Ipv4Header const &ipHeader,
                              Packet packet,
                              RouteReplyCallback routeReply);
 
+/**
+ * @brief Check to see if we can determine the interface index that will be
+ * used if a packet is sent to this destination.
+ *
+ * This method addresses a problem in the IP stack where a destination address
+ * must be present and checksummed into the IP header before the actual 
+ * interface over which the packet is sent can be determined.  The answer is
+ * to implement a known and intentional cross-layer violation.  This is the
+ * endpoint of a call chain that started up quite high in the stack (sockets)
+ * and has found its way down to the Ipv4L3Protocol which is consulting the
+ * routing protocols for what they would do if presented with a packet of the
+ * given destination.
+ *
+ * Note that the a single interface index is returned.  This means that if
+ * the destination address is a multicast, and an explicit route is present
+ * that includeds multiple output interfaces, that route cannot be used.
+ * 
+ * If there are multiple paths out of the node, the resolution is performed
+ * by Ipv4L3Protocol::GetIfIndexforDestination which has access to more 
+ * contextual information that is useful for making a determination.
+ *
+ * @param destination The Ipv4Address if the destination of a hypothetical 
+ * packet.  This may be a multicast group address.
+ * @param ifIndex A reference to the interface index over which a packet
+ * sent to this destination would be sent.
+ * @return Returns true if a route is found to the destination that involves
+ * a single output interface index, otherwise returns false indicating that
+ * the next routing protocol should be consulted.  In practice, the static 
+ * routing protocol is the last chance protocol.
+ *
+ * @see Ipv4StaticRouting
+ * @see Ipv4RoutingProtocol
+ * @see Ipv4L3Protocol
+ */
+  virtual bool RequestIfIndex (Ipv4Address destination, uint32_t& ifIndex);
 
+/**
+ * @brief Add a host route to the static routing table.
+ *
+ * @param dest The Ipv4Address destination for this route.
+ * @param nextHop The Ipv4Address of the next hop in the route.
+ * @param interface The network interface index used to send packets to the
+ * destination.
+ *
+ * @see Ipv4Address
+ */
   void AddHostRouteTo (Ipv4Address dest, 
                        Ipv4Address nextHop, 
                        uint32_t interface);
+/**
+ * @brief Add a host route to the static routing table.
+ *
+ * @param dest The Ipv4Address destination for this route.
+ * @param interface The network interface index used to send packets to the
+ * destination.
+ *
+ * @see Ipv4Address
+ */
   void AddHostRouteTo (Ipv4Address dest, 
                        uint32_t interface);
 
+/**
+ * @brief Add a network route to the static routing table.
+ *
+ * @param network The Ipv4Address network for this route.
+ * @param networkmask The Ipv4Mask to extract the network.
+ * @param nextHop The next hop in the route to the destination network.
+ * @param interface The network interface index used to send packets to the
+ * destination.
+ *
+ * @see Ipv4Address
+ */
   void AddNetworkRouteTo (Ipv4Address network, 
                           Ipv4Mask networkMask, 
                           Ipv4Address nextHop, 
                           uint32_t interface);
+
+/**
+ * @brief Add a network route to the static routing table.
+ *
+ * @param network The Ipv4Address network for this route.
+ * @param networkmask The Ipv4Mask to extract the network.
+ * @param interface The network interface index used to send packets to the
+ * destination.
+ *
+ * @see Ipv4Address
+ */
   void AddNetworkRouteTo (Ipv4Address network, 
                           Ipv4Mask networkMask, 
                           uint32_t interface);
+
+/**
+ * @brief Add a default route to the static routing table.
+ *
+ * This method tells the routing system what to do in the case where a specific
+ * route to a destination is not found.  The system forwards packets to the
+ * specified node in the hope that it knows better how to route the packet.
+ * 
+ * If the default route is set, it is returned as the selected route from 
+ * LookupStatic irrespective of destination address if no specific route is
+ * found.
+ *
+ * @param nextHop The Ipv4Address to send packets to in the hope that they
+ * will be forwarded correctly.
+ * @param interface The network interface index used to send packets.
+ *
+ * @see Ipv4Address
+ * @see Ipv4StaticRouting::Lookup
+ */
   void SetDefaultRoute (Ipv4Address nextHop, 
                         uint32_t interface);
+
+/**
+ * @brief Get the number of individual unicast routes that have been added
+ * to the routing table.
+ *
+ * @warning The default route counts as one of the routes.
+ */
   uint32_t GetNRoutes (void);
+
+/**
+ * @brief Get the default route from the static routing table.
+ *
+ * @return If the default route is set, a pointer to that Ipv4Route is
+ * returned, otherwise a zero pointer is returned.
+ *
+ * @see Ipv4Route
+ */
+  Ipv4Route *GetDefaultRoute (void);
+
+/**
+ * @brief Get a route from the static unicast routing table.
+ *
+ * Externally, the unicast static routing table appears simply as a table with
+ * n entries.  The one sublety of note is that if a default route has been set
+ * it will appear as the zeroth entry in the table.  This means that if you
+ * add only a default route, the table will have one entry that can be accessed
+ * either by explicity calling GetDefaultRoute () or by calling GetRoute (0).
+ * 
+ * Similarly, if the default route has been set, calling RemoveRoute (0) will
+ * remove the default route.
+ *
+ * @param i The index (into the routing table) of the route to retrieve.  If
+ * the default route has been set, it will occupy index zero.
+ * @return If route is set, a pointer to that Ipv4Route is returned, otherwise
+ * a zero pointer is returned.
+ *
+ * @see Ipv4Route
+ * @see Ipv4StaticRouting::RemoveRoute
+ */
   Ipv4Route *GetRoute (uint32_t i);
+
+/**
+ * @brief Remove a route from the static unicast routing table.
+ *
+ * Externally, the unicast static routing table appears simply as a table with
+ * n entries.  The one sublety of note is that if a default route has been set
+ * it will appear as the zeroth entry in the table.  This means that if the
+ * default route has been set, calling RemoveRoute (0) will remove the
+ * default route.
+ *
+ * @param i The index (into the routing table) of the route to remove.  If
+ * the default route has been set, it will occupy index zero.
+ *
+ * @see Ipv4Route
+ * @see Ipv4StaticRouting::GetRoute
+ * @see Ipv4StaticRouting::AddRoute
+ */
   void RemoveRoute (uint32_t i);
 
+/**
+ * @brief Add a multicast route to the static routing table.
+ *
+ * A multicast route must specify an origin IP address, a multicast group and
+ * an input network interface index as conditions and provide a vector of
+ * output network interface indices over which packets matching the conditions
+ * are sent.
+ *
+ * Typically there are two main types of multicast routes:  routes of the 
+ * first kind are used during forwarding.  All of the conditions must be
+ * exlicitly provided.  The second kind of routes are used to get packets off
+ * of a local node.  The difference is in the input interface.  Routes for
+ * forwarding will always have an explicit input interface specified.  Routes
+ * off of a node will always set the input interface to a wildcard specified
+ * by the index Ipv4RoutingProtocol::IF_INDEX_ANY.
+ *
+ * For routes off of a local node wildcards may be used in the origin and
+ * multicast group addresses.  The wildcard used for Ipv4Adresses is that 
+ * address returned by Ipv4Address::GetAny () -- typically "0.0.0.0".  Usage
+ * of a wildcard allows one to specify default behavior to varying degrees.
+ *
+ * For example, making the origin address a wildcard, but leaving the 
+ * multicast group specific allows one (in the case of a node with multiple
+ * interfaces) to create different routes using different output interfaces
+ * for each multicast group.
+ *
+ * If the origin and multicast addresses are made wildcards, you have created
+ * essentially a default multicast address that can forward to multiple 
+ * interfaces.  Compare this to the actual default multicast address that is
+ * limited to specifying a single output interface for compatibility with
+ * existing functionality in other systems.
+ * 
+ * @param origin The Ipv4Address of the origin of packets for this route.  May
+ * be Ipv4Address:GetAny for open groups.
+ * @param group The Ipv4Address of the multicast group or this route.
+ * @param inputInterface The input network interface index over which to 
+ * expect packets destined for this route.  May be
+ * Ipv4RoutingProtocol::IF_INDEX_ANY for packets of local origin.
+ * @param outputInterface A vector of network interface indices used to specify
+ * how to send packets to the destination(s).
+ *
+ * @see Ipv4Address
+ */
+  void AddMulticastRoute (Ipv4Address origin,
+                          Ipv4Address group,
+                          uint32_t inputInterface,
+                          std::vector<uint32_t> outputInterfaces);
+
+/**
+ * @brief Add a default multicast route to the static routing table.
+ *
+ * This is the multicast equivalent of the unicast version SetDefaultRoute.
+ * We tell the routing system what to do in the case where a specific route
+ * to a destination multicast group is not found.  The system forwards 
+ * packets out the specified interface in the hope that "something out there"
+ * knows better how to route the packet.  This method is only used in 
+ * initially sending packets off of a host.  The default multicast route is
+ * not consulted during forwarding -- exact routes must be specified using
+ * AddMulticastRoute for that case.
+ *
+ * Since we're basically sending packets to some entity we think may know
+ * better what to do, we don't pay attention to "subtleties" like origin
+ * address, nor do we worry about forwarding out multiple  interfaces.  If the
+ * default multicast route is set, it is returned as the selected route from 
+ * LookupStatic irrespective of origin or multicast group if another specific
+ * route is not found.
+ *
+ * @param outputInterface The network interface index used to specify where
+ * to send packets in the case of unknown routes.
+ *
+ * @see Ipv4Address
+ */
+  void SetDefaultMulticastRoute (uint32_t outputInterface);
+
+/**
+ * @brief Get the number of individual multicast routes that have been added
+ * to the routing table.
+ *
+ * @warning The default multicast route counts as one of the routes.
+ */
+  uint32_t GetNMulticastRoutes (void) const;
+
+/**
+ * @brief Get a route from the static multicast routing table.
+ *
+ * Externally, the multicast static routing table appears simply as a table 
+ * with n entries.  The one sublety of note is that if a default route has 
+ * been set it will appear as the zeroth entry in the table.  This means that 
+ * if you add only a default route, the table will have one entry that can be
+ * accessed either by explicity calling GetDefaultMulticastRoute () or by
+ * calling GetMulticastRoute (0).
+ * 
+ * Similarly, if the default route has been set, calling 
+ * RemoveMulticastRoute (0) will remove the default route.
+ *
+ * @param i The index (into the routing table) of the multicast route to
+ * retrieve.  If the default route has been set, it will occupy index zero.
+ * @return If route <i> is set, a pointer to that Ipv4MulticastRoute is
+ * returned, otherwise a zero pointer is returned.
+ *
+ * @see Ipv4MulticastRoute
+ * @see Ipv4StaticRouting::RemoveRoute
+ */
+  Ipv4MulticastRoute *GetMulticastRoute (uint32_t i) const;
+
+/**
+ * @brief Get the default multicast route from the static routing table.
+ *
+ * @return If the default route is set, a pointer to that Ipv4MulticastRoute is
+ * returned, otherwise a zero pointer is returned.
+ *
+ * @see Ipv4Route
+ */
+  Ipv4MulticastRoute *GetDefaultMulticastRoute (void) const;
+
+/**
+ * @brief Remove a route from the static multicast routing table.
+ *
+ * Externally, the multicast static routing table appears simply as a table 
+ * with n entries.  The one sublety of note is that if a default multicast
+ * route has been set it will appear as the zeroth entry in the table.  This
+ * means that the default route may be removed by calling this method with
+ * appropriate wildcard parameters.
+ *
+ * This method causes the multicast routing table to be searched for the first
+ * route that matches the parameters and removes it.
+ *
+ * Wildcards may be provided to this function, but the wildcards are used to
+ * exacly match wildcards in the routes (see AddMulticastRoute).  That is,
+ * calling RemoveMulticastRoute with the origin set to "0.0.0.0" will not
+ * remove routes with any address in the origin, but will only remove routes
+ * with "0.0.0.0" set as the the origin.
+ *
+ * @param origin The IP address specified as the origin of packets for the
+ * route.
+ * @param origin The IP address specified as the multicast group addres of
+ * the route.
+ * @param inputInterfade The network interface index specified as the expected
+ * input interface for the route.
+ * @returns True if a route was found and removed, false otherwise.
+ *
+ * @see Ipv4MulticastRoute
+ * @see Ipv4StaticRouting::AddMulticastRoute
+ */
+  bool RemoveMulticastRoute (Ipv4Address origin,
+                             Ipv4Address group,
+                             uint32_t inputInterface);
+
+/**
+ * @brief Remove a route from the static multicast routing table.
+ *
+ * Externally, the multicast static routing table appears simply as a table 
+ * with n entries.  The one sublety of note is that if a default multicast
+ * route has been set it will appear as the zeroth entry in the table.  This 
+ * means that if the default route has been set, calling 
+ * RemoveMulticastRoute (0) will remove the default route.
+ *
+ * @param index The index (into the multicast routing table) of the route to
+ * remove.  If the default route has been set, it will occupy index zero.
+ *
+ * @see Ipv4Route
+ * @see Ipv4StaticRouting::GetRoute
+ * @see Ipv4StaticRouting::AddRoute
+ */
+  void RemoveMulticastRoute (uint32_t index);
+
 protected:
   void DoDispose (void);
 
@@ -86,15 +491,21 @@
   typedef std::list<Ipv4Route *>::const_iterator NetworkRoutesCI;
   typedef std::list<Ipv4Route *>::iterator NetworkRoutesI;
 
+  typedef std::list<Ipv4MulticastRoute *> MulticastRoutes;
+  typedef std::list<Ipv4MulticastRoute *>::const_iterator MulticastRoutesCI;
+  typedef std::list<Ipv4MulticastRoute *>::iterator MulticastRoutesI;
+
   Ipv4Route *LookupStatic (Ipv4Address dest);
+  Ipv4MulticastRoute *LookupStatic (Ipv4Address origin, Ipv4Address group,
+                                    uint32_t ifIndex);
 
   HostRoutes m_hostRoutes;
   NetworkRoutes m_networkRoutes;
   Ipv4Route *m_defaultRoute;
+  Ipv4MulticastRoute *m_defaultMulticastRoute;
+  MulticastRoutes m_multicastRoutes;
 };
 
-
-
 } // Namespace ns3
 
 #endif /* IPV4_STATIC_ROUTING_H */
--- a/src/internet-node/udp-l4-protocol.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/internet-node/udp-l4-protocol.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -19,6 +19,7 @@
  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
  */
 
+#include "ns3/debug.h"
 #include "ns3/assert.h"
 #include "ns3/packet.h"
 #include "ns3/node.h"
@@ -30,6 +31,8 @@
 #include "ipv4-l3-protocol.h"
 #include "udp-socket.h"
 
+NS_DEBUG_COMPONENT_DEFINE ("UdpL4Protocol");
+
 namespace ns3 {
 
 /* see http://www.iana.org/assignments/protocol-numbers */
@@ -39,14 +42,19 @@
   : Ipv4L4Protocol (PROT_NUMBER, 2),
     m_node (node),
     m_endPoints (new Ipv4EndPointDemux ())
-{}
+{
+  NS_DEBUG("UdpL4Protocol::UdpL4Protocol ()");
+}
 
 UdpL4Protocol::~UdpL4Protocol ()
-{}
+{
+  NS_DEBUG("UdpL4Protocol::~UdpL4Protocol ()");
+}
 
 void
 UdpL4Protocol::DoDispose (void)
 {
+  NS_DEBUG("UdpL4Protocol::DoDispose ()");
   if (m_endPoints != 0)
     {
       delete m_endPoints;
@@ -59,6 +67,7 @@
 Ptr<Socket>
 UdpL4Protocol::CreateSocket (void)
 {
+  NS_DEBUG("UdpL4Protocol::CreateSocket ()");
   Ptr<Socket> socket = Create<UdpSocket> (m_node, this);
   return socket;
 }
@@ -66,27 +75,36 @@
 Ipv4EndPoint *
 UdpL4Protocol::Allocate (void)
 {
+  NS_DEBUG("UdpL4Protocol::Allocate ()");
   return m_endPoints->Allocate ();
 }
+
 Ipv4EndPoint *
 UdpL4Protocol::Allocate (Ipv4Address address)
 {
+  NS_DEBUG("UdpL4Protocol::Allocate (" << address << ")");
   return m_endPoints->Allocate (address);
 }
+
 Ipv4EndPoint *
 UdpL4Protocol::Allocate (uint16_t port)
 {
+  NS_DEBUG("UdpL4Protocol::Allocate (" << port << ")");
   return m_endPoints->Allocate (port);
 }
+
 Ipv4EndPoint *
 UdpL4Protocol::Allocate (Ipv4Address address, uint16_t port)
 {
+  NS_DEBUG("UdpL4Protocol::Allocate (" << address << ", " << port << ")");
   return m_endPoints->Allocate (address, port);
 }
 Ipv4EndPoint *
 UdpL4Protocol::Allocate (Ipv4Address localAddress, uint16_t localPort,
                Ipv4Address peerAddress, uint16_t peerPort)
 {
+  NS_DEBUG("UdpL4Protocol::Allocate (" << localAddress << ", " << localPort <<
+    ", " << peerAddress << ", " << peerPort << ")");
   return m_endPoints->Allocate (localAddress, localPort,
                                 peerAddress, peerPort);
 }
@@ -94,6 +112,7 @@
 void 
 UdpL4Protocol::DeAllocate (Ipv4EndPoint *endPoint)
 {
+  NS_DEBUG("UdpL4Protocol::Deallocate (" << endPoint << ")");
   m_endPoints->DeAllocate (endPoint);
 }
 
@@ -102,6 +121,9 @@
              Ipv4Address const &source,
              Ipv4Address const &destination)
 {
+  NS_DEBUG("UdpL4Protocol::Receive (" << &packet << ", " << source <<
+    ", " << destination << ")");
+
   UdpHeader udpHeader;
   packet.RemoveHeader (udpHeader);
   Ipv4EndPointDemux::EndPoints endPoints =
@@ -119,6 +141,9 @@
            Ipv4Address saddr, Ipv4Address daddr, 
            uint16_t sport, uint16_t dport)
 {
+  NS_DEBUG("UdpL4Protocol::Send (" << &packet << ", " << saddr <<
+    ", " << daddr << ", " << sport << ", " << dport << ")");
+
   UdpHeader udpHeader;
   udpHeader.SetDestination (dport);
   udpHeader.SetSource (sport);
@@ -132,6 +157,7 @@
   Ptr<Ipv4L3Protocol> ipv4 = m_node->QueryInterface<Ipv4L3Protocol> (Ipv4L3Protocol::iid);
   if (ipv4 != 0)
     {
+      NS_DEBUG("UdpL4Protocol::Send (): Sending to IP");
       ipv4->Send (packet, saddr, daddr, PROT_NUMBER);
     }
 }
--- a/src/internet-node/udp-socket.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/internet-node/udp-socket.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -18,6 +18,8 @@
  *
  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
  */
+
+#include "ns3/debug.h"
 #include "ns3/node.h"
 #include "ns3/inet-socket-address.h"
 #include "ns3/ipv4-route.h"
@@ -26,6 +28,9 @@
 #include "udp-l4-protocol.h"
 #include "ipv4-end-point.h"
 #include "ipv4-l4-demux.h"
+#include "ns3/ipv4.h"
+
+NS_DEBUG_COMPONENT_DEFINE ("UdpSocket");
 
 namespace ns3 {
 
@@ -37,9 +42,14 @@
     m_shutdownSend (false),
     m_shutdownRecv (false),
     m_connected (false)
-{}
+{
+  NS_DEBUG("UdpSocket::UdpSocket ()");
+}
+
 UdpSocket::~UdpSocket ()
 {
+  NS_DEBUG("UdpSocket::~UdpSocket ()");
+
   m_node = 0;
   if (m_endPoint != 0)
     {
@@ -62,25 +72,32 @@
 enum Socket::SocketErrno
 UdpSocket::GetErrno (void) const
 {
+  NS_DEBUG("UdpSocket::GetErrno ()");
+
   return m_errno;
 }
 
 Ptr<Node>
 UdpSocket::GetNode (void) const
 {
+  NS_DEBUG("UdpSocket::GetNode ()");
   return m_node;
 }
 
 void 
 UdpSocket::Destroy (void)
 {
+  NS_DEBUG("UdpSocket::Destroy ()");
   m_node = 0;
   m_endPoint = 0;
   m_udp = 0;
 }
+
 int
 UdpSocket::FinishBind (void)
 {
+  NS_DEBUG("UdpSocket::FinishBind ()");
+
   if (m_endPoint == 0)
     {
       return -1;
@@ -93,14 +110,20 @@
 int
 UdpSocket::Bind (void)
 {
+  NS_DEBUG("UdpSocket::Bind ()");
+
   m_endPoint = m_udp->Allocate ();
   return FinishBind ();
 }
+
 int 
 UdpSocket::Bind (const Address &address)
 {
+  NS_DEBUG("UdpSocket::Bind (" << address << ")");
+
   if (!InetSocketAddress::IsMatchingType (address))
     {
+      NS_DEBUG("UdpSocket::Bind (): Not IsMatchingType");
       return ERROR_INVAL;
     }
   InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
@@ -129,12 +152,15 @@
 int 
 UdpSocket::ShutdownSend (void)
 {
+  NS_DEBUG("UdpSocket::ShutDownSend ()");
   m_shutdownSend = true;
   return 0;
 }
+
 int 
 UdpSocket::ShutdownRecv (void)
 {
+  NS_DEBUG("UdpSocket::ShutDownRecv ()");
   m_shutdownRecv = false;
   return 0;
 }
@@ -142,6 +168,7 @@
 int
 UdpSocket::Close(void)
 {
+  NS_DEBUG("UdpSocket::Close ()");
   NotifyCloseCompleted ();
   return 0;
 }
@@ -149,24 +176,36 @@
 int
 UdpSocket::Connect(const Address & address)
 {
+  NS_DEBUG ("UdpSocket::Connect (" << address << ")");
   Ipv4Route routeToDest;
   InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
   m_defaultAddress = transport.GetIpv4 ();
   m_defaultPort = transport.GetPort ();
   NotifyConnectionSucceeded ();
   m_connected = true;
-  if (GetIpv4RouteToDestination (m_node, routeToDest, m_defaultAddress) )
+
+  NS_DEBUG ("UdpSocket::Connect (): Updating local address");
+
+  uint32_t localIfIndex;
+
+  Ptr<Ipv4> ipv4 = m_node->QueryInterface<Ipv4> (Ipv4::iid);
+  
+  if (ipv4->GetIfIndexForDestination (m_defaultAddress, localIfIndex))
     {
-      uint32_t localIfIndex = routeToDest.GetInterface ();
-      Ptr<Ipv4> ipv4 = m_node->QueryInterface<Ipv4> (Ipv4::iid);
-      m_endPoint->SetLocalAddress (ipv4->GetAddress(localIfIndex) );
+      m_endPoint->SetLocalAddress (ipv4->GetAddress(localIfIndex));
     }
+
+  NS_DEBUG ("UdpSocket::Connect (): Local address is " << 
+    m_endPoint->GetLocalAddress());
+
   return 0;
 }
 
 int 
 UdpSocket::Send (const Packet &p)
 {
+  NS_DEBUG("UdpSocket::Send (" << &p << ")");
+
   if (!m_connected)
     {
       m_errno = ERROR_NOTCONN;
@@ -196,12 +235,14 @@
   return DoSendTo (p, m_defaultAddress, m_defaultPort);
 }
 
-
 int
 UdpSocket::DoSendTo (const Packet &p, const Address &address)
 {
+  NS_DEBUG("UdpSocket::DoSendTo (" << &p << ", " << address << ")");
+
   if (!m_connected)
     {
+      NS_DEBUG("UdpSocket::DoSendTo (): Not connected");
       InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
       Ipv4Address ipv4 = transport.GetIpv4 ();
       uint16_t port = transport.GetPort ();
@@ -210,13 +251,19 @@
   else
     {
       // connected UDP socket must use default addresses
+      NS_DEBUG("UdpSocket::DoSendTo (): Connected");
       return DoSendTo (p, m_defaultAddress, m_defaultPort);
     }
 }
+
 int
 UdpSocket::DoSendTo (const Packet &p, Ipv4Address dest, uint16_t port)
 {
+  NS_DEBUG("UdpSocket::DoSendTo (" << &p << ", " << dest << ", " <<
+    port << ")");
+
   Ipv4Route routeToDest;
+
   if (m_endPoint == 0)
     {
       if (Bind () == -1)
@@ -231,13 +278,17 @@
       m_errno = ERROR_SHUTDOWN;
       return -1;
     }
+
+  uint32_t localIfIndex;
+  Ptr<Ipv4> ipv4 = m_node->QueryInterface<Ipv4> (Ipv4::iid);
+
   //
   // If dest is sent to the limited broadcast address (all ones),
   // convert it to send a copy of the packet out of every interface
   //
   if (dest.IsBroadcast ())
     {
-      Ptr<Ipv4> ipv4 = m_node->QueryInterface<Ipv4> (Ipv4::iid);
+      NS_DEBUG("UdpSocket::DoSendTo (): Limited broadcast");
       for (uint32_t i = 0; i < ipv4->GetNInterfaces (); i++ )
         {
           Ipv4Address addri = ipv4->GetAddress (i);
@@ -247,10 +298,9 @@
           NotifyDataSent (p.GetSize ());
         }
     }
-  else if (GetIpv4RouteToDestination (m_node, routeToDest, dest) )
+  else if (ipv4->GetIfIndexForDestination(dest, localIfIndex))
     {
-      uint32_t localIfIndex = routeToDest.GetInterface ();
-      Ptr<Ipv4> ipv4 = m_node->QueryInterface<Ipv4> (Ipv4::iid);
+      NS_DEBUG("UdpSocket::DoSendTo (): Route exists");
       m_udp->Send (p, ipv4->GetAddress (localIfIndex), dest,
 		   m_endPoint->GetLocalPort (), port);
       NotifyDataSent (p.GetSize ());
@@ -258,15 +308,18 @@
     }
   else
    {
+      NS_DEBUG("UdpSocket::DoSendTo (): ERROR_NOROUTETOHOST");
       m_errno = ERROR_NOROUTETOHOST;
       return -1;
    }
+
   return 0;
 }
 
 int 
 UdpSocket::SendTo(const Address &address, const Packet &p)
 {
+  NS_DEBUG("UdpSocket::SendTo (" << address << ", " << &p << ")");
   InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
   Ipv4Address ipv4 = transport.GetIpv4 ();
   uint16_t port = transport.GetPort ();
@@ -276,6 +329,9 @@
 void 
 UdpSocket::ForwardUp (const Packet &packet, Ipv4Address ipv4, uint16_t port)
 {
+  NS_DEBUG("UdpSocket::ForwardUp (" << &packet << ", " << ipv4 << ", " <<
+    port << ")");
+
   if (m_shutdownRecv)
     {
       return;
@@ -286,4 +342,4 @@
   NotifyDataReceived (p, address);
 }
 
-}//namespace ns3
+} //namespace ns3
--- a/src/mobility/grid-topology.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/grid-topology.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -1,7 +1,6 @@
 /* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
 /*
  * Copyright (c) 2007 INRIA
- * All rights reserved.
  *
  * 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
--- a/src/mobility/grid-topology.h	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/grid-topology.h	Wed Sep 12 18:06:09 2007 +0100
@@ -1,7 +1,6 @@
 /* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
 /*
  * Copyright (c) 2007 INRIA
- * All rights reserved.
  *
  * 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
--- a/src/mobility/hierarchical-mobility-model.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/hierarchical-mobility-model.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -1,7 +1,6 @@
 /* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
 /*
  * Copyright (c) 2007 INRIA
- * All rights reserved.
  *
  * 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
--- a/src/mobility/hierarchical-mobility-model.h	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/hierarchical-mobility-model.h	Wed Sep 12 18:06:09 2007 +0100
@@ -1,7 +1,6 @@
 /* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
 /*
  * Copyright (c) 2007 INRIA
- * All rights reserved.
  *
  * 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
--- a/src/mobility/mobility-model-notifier.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/mobility-model-notifier.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -1,7 +1,6 @@
 /* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
 /*
  * Copyright (c) 2007 INRIA
- * All rights reserved.
  *
  * 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
--- a/src/mobility/mobility-model-notifier.h	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/mobility-model-notifier.h	Wed Sep 12 18:06:09 2007 +0100
@@ -1,7 +1,6 @@
 /* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
 /*
  * Copyright (c) 2007 INRIA
- * All rights reserved.
  *
  * 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
--- a/src/mobility/mobility-model.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/mobility-model.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -1,7 +1,6 @@
 /* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
 /*
  * Copyright (c) 2006,2007 INRIA
- * All rights reserved.
  *
  * 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
--- a/src/mobility/mobility-model.h	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/mobility-model.h	Wed Sep 12 18:06:09 2007 +0100
@@ -1,7 +1,6 @@
 /* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
 /*
  * Copyright (c) 2006,2007 INRIA
- * All rights reserved.
  *
  * 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
--- a/src/mobility/position.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/position.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -1,3 +1,22 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ *
+ * 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@sophia.inria.fr>
+ */
 #include "position.h"
 #include <cmath>
 
--- a/src/mobility/position.h	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/position.h	Wed Sep 12 18:06:09 2007 +0100
@@ -1,4 +1,22 @@
 /* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ *
+ * 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@sophia.inria.fr>
+ */
 #ifndef POSITION_H
 #define POSITION_H
 
--- a/src/mobility/random-position.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/random-position.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -1,3 +1,22 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ *
+ * 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@sophia.inria.fr>
+ */
 #include "random-position.h"
 #include "ns3/random-variable.h"
 #include "ns3/default-value.h"
--- a/src/mobility/random-position.h	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/random-position.h	Wed Sep 12 18:06:09 2007 +0100
@@ -1,4 +1,22 @@
 /* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ *
+ * 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@sophia.inria.fr>
+ */
 #ifndef RANDOM_POSITION_H
 #define RANDOM_POSITION_H
 
--- a/src/mobility/rectangle-default-value.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/rectangle-default-value.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -1,7 +1,6 @@
 /* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
 /*
  * Copyright (c) 2007 INRIA
- * All rights reserved.
  *
  * 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
--- a/src/mobility/rectangle-default-value.h	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/rectangle-default-value.h	Wed Sep 12 18:06:09 2007 +0100
@@ -1,7 +1,6 @@
 /* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
 /*
  * Copyright (c) 2007 INRIA
- * All rights reserved.
  *
  * 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
--- a/src/mobility/rectangle.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/rectangle.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -1,7 +1,6 @@
 /* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
 /*
  * Copyright (c) 2007 INRIA
- * All rights reserved.
  *
  * 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
--- a/src/mobility/rectangle.h	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/rectangle.h	Wed Sep 12 18:06:09 2007 +0100
@@ -1,7 +1,6 @@
 /* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
 /*
  * Copyright (c) 2007 INRIA
- * All rights reserved.
  *
  * 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
--- a/src/mobility/speed.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/speed.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -1,3 +1,22 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ *
+ * 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@sophia.inria.fr>
+ */
 #include "speed.h"
 
 namespace ns3 {
--- a/src/mobility/speed.h	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/speed.h	Wed Sep 12 18:06:09 2007 +0100
@@ -1,4 +1,22 @@
 /* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ *
+ * 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@sophia.inria.fr>
+ */
 #ifndef SPEED_H
 #define SPEED_H
 
--- a/src/mobility/static-mobility-model.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/static-mobility-model.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -1,7 +1,6 @@
 /* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2006 INRIA
- * All rights reserved.
+ * Copyright (c) 2006,2007 INRIA
  *
  * 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
--- a/src/mobility/static-mobility-model.h	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/static-mobility-model.h	Wed Sep 12 18:06:09 2007 +0100
@@ -1,7 +1,6 @@
 /* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
 /*
  * Copyright (c) 2006,2007 INRIA
- * All rights reserved.
  *
  * 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
--- a/src/mobility/static-speed-helper.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/static-speed-helper.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -1,3 +1,22 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006,2007 INRIA
+ *
+ * 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@sophia.inria.fr>
+ */
 #include "ns3/simulator.h"
 #include "ns3/rectangle.h"
 #include "static-speed-helper.h"
--- a/src/mobility/static-speed-helper.h	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/static-speed-helper.h	Wed Sep 12 18:06:09 2007 +0100
@@ -1,4 +1,22 @@
 /* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006,2007 INRIA
+ *
+ * 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@sophia.inria.fr>
+ */
 #ifndef STATIC_SPEED_HELPER_H
 #define STATIC_SPEED_HELPER_H
 
--- a/src/mobility/static-speed-mobility-model.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/static-speed-mobility-model.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -1,7 +1,6 @@
 /* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
 /*
  * Copyright (c) 2006, 2007 INRIA
- * All rights reserved.
  *
  * 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
--- a/src/mobility/static-speed-mobility-model.h	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/static-speed-mobility-model.h	Wed Sep 12 18:06:09 2007 +0100
@@ -1,7 +1,6 @@
 /* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
 /*
  * Copyright (c) 2006, 2007 INRIA
- * All rights reserved.
  *
  * 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
--- a/src/node/ipv4-route.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/node/ipv4-route.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -30,6 +30,7 @@
 
 Ipv4Route::Ipv4Route ()
 {}
+
 Ipv4Route::Ipv4Route (Ipv4Route const &route)
   : m_dest (route.m_dest),
     m_destNetworkMask (route.m_destNetworkMask),
@@ -37,6 +38,13 @@
     m_interface (route.m_interface)
 {}
 
+Ipv4Route::Ipv4Route (Ipv4Route const *route)
+  : m_dest (route->m_dest),
+    m_destNetworkMask (route->m_destNetworkMask),
+    m_gateway (route->m_gateway),
+    m_interface (route->m_interface)
+{}
+
 Ipv4Route::Ipv4Route (Ipv4Address dest,
                       Ipv4Address gateway,
                       uint32_t interface)
@@ -137,7 +145,6 @@
   return m_interface;
 }
 
-
 Ipv4Route 
 Ipv4Route::CreateHostRouteTo (Ipv4Address dest, 
 			      Ipv4Address nextHop, 
@@ -220,4 +227,108 @@
   return os;
 }
 
+/*****************************************************
+ *     Ipv4MulticastRoute
+ *****************************************************/
+
+Ipv4MulticastRoute::Ipv4MulticastRoute ()
+{
+}
+
+Ipv4MulticastRoute::Ipv4MulticastRoute (Ipv4MulticastRoute const &route)
+: 
+  m_origin (route.m_origin),
+  m_group (route.m_group),
+  m_inputInterface (route.m_inputInterface),
+  m_outputInterfaces (route.m_outputInterfaces)
+{
+}
+
+Ipv4MulticastRoute::Ipv4MulticastRoute (Ipv4MulticastRoute const *route)
+: 
+  m_origin (route->m_origin),
+  m_group (route->m_group),
+  m_inputInterface (route->m_inputInterface),
+  m_outputInterfaces (route->m_outputInterfaces)
+{
+}
+
+Ipv4MulticastRoute::Ipv4MulticastRoute (
+  Ipv4Address origin, 
+  Ipv4Address group, 
+  uint32_t inputInterface, 
+  std::vector<uint32_t> outputInterfaces)
+{
+  m_origin = origin;
+  m_group = group;
+  m_inputInterface = inputInterface;
+  m_outputInterfaces = outputInterfaces;
+}
+
+Ipv4Address 
+Ipv4MulticastRoute::GetOrigin (void) const
+{
+  return m_origin;
+}
+
+Ipv4Address 
+Ipv4MulticastRoute::GetGroup (void) const
+{
+  return m_group;
+}
+
+uint32_t 
+Ipv4MulticastRoute::GetInputInterface (void) const
+{
+  return m_inputInterface;
+}
+
+uint32_t
+Ipv4MulticastRoute::GetNOutputInterfaces (void) const
+{
+  return m_outputInterfaces.size ();
+}
+
+uint32_t
+Ipv4MulticastRoute::GetOutputInterface (uint32_t n) const
+{
+  NS_ASSERT_MSG(n < m_outputInterfaces.size (), 
+    "Ipv4MulticastRoute::GetOutputInterface (): index out of bounds");
+
+  return m_outputInterfaces[n];
+}
+
+std::vector<uint32_t>
+Ipv4MulticastRoute::GetOutputInterfaces (void) const
+{
+  return m_outputInterfaces;
+}
+
+Ipv4MulticastRoute 
+Ipv4MulticastRoute::CreateMulticastRoute (
+  Ipv4Address origin, 
+  Ipv4Address group, 
+  uint32_t inputInterface,
+  std::vector<uint32_t> outputInterfaces)
+{
+  return Ipv4MulticastRoute (origin, group, inputInterface, outputInterfaces);
+}
+
+std::ostream& 
+operator<< (std::ostream& os, Ipv4MulticastRoute const& route)
+{
+  os << "origin=" << route.GetOrigin () << 
+    ", group=" << route.GetGroup () <<
+    ", input interface=" << route.GetInputInterface () <<
+    ", output interfaces=";
+
+  for (uint32_t i = 0; i < route.GetNOutputInterfaces (); ++i)
+    {
+      os << route.GetOutputInterface (i) << " ";
+
+    }
+
+  return os;
+}
+
 }//namespace ns3
--- a/src/node/ipv4-route.h	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/node/ipv4-route.h	Wed Sep 12 18:06:09 2007 +0100
@@ -22,6 +22,7 @@
 #define IPV4_ROUTE_H
 
 #include <list>
+#include <vector>
 #include <ostream>
 
 #include "ipv4-address.h"
@@ -36,12 +37,19 @@
    * \brief This constructor does nothing
    */
   Ipv4Route ();
+
   /**
    * \brief Copy Constructor
    * \param route The route to copy
    */
   Ipv4Route (Ipv4Route const &route);
 
+  /**
+   * \brief Copy Constructor
+   * \param route The route to copy
+   */
+  Ipv4Route (Ipv4Route const *route);
+
   bool IsHost (void) const;
   /**
    * \return The IPv4 address of the destination of this route
@@ -98,6 +106,74 @@
 
 std::ostream& operator<< (std::ostream& os, Ipv4Route const& route);
 
+/**
+ * \brief A record of an IPv4 multicast route
+ */
+class Ipv4MulticastRoute {
+public:
+  /**
+   * \brief This constructor does nothing
+   */
+  Ipv4MulticastRoute ();
+
+  /**
+   * \brief Copy Constructor
+   * \param route The route to copy
+   */
+  Ipv4MulticastRoute (Ipv4MulticastRoute const &route);
+
+  /**
+   * \brief Copy Constructor
+   * \param route The route to copy
+   */
+  Ipv4MulticastRoute (Ipv4MulticastRoute const *route);
+
+  /**
+   * \return The IPv4 address of the source of this route
+   */
+  Ipv4Address GetOrigin (void) const;
+
+  /**
+   * \return The IPv4 address of the multicast group of this route
+   */
+  Ipv4Address GetGroup (void) const;
+
+  /**
+   * \return The IPv4 address of the input interface of this route
+   */
+  uint32_t GetInputInterface (void) const;
+
+  /**
+   * \return The number of output interfaces of this route
+   */
+  uint32_t GetNOutputInterfaces (void) const;
+
+  /**
+   * \return A specified output interface.
+   */
+  uint32_t GetOutputInterface (uint32_t n) const;
+
+  /**
+   * \return A vector of all of the output interfaces of this route.
+   */
+  std::vector<uint32_t> GetOutputInterfaces (void) const;
+
+  static Ipv4MulticastRoute CreateMulticastRoute (Ipv4Address origin, 
+    Ipv4Address group, uint32_t inputInterface,
+    std::vector<uint32_t> outputInterfaces);
+
+private:
+  Ipv4MulticastRoute (Ipv4Address origin, Ipv4Address group, 
+    uint32_t inputInterface, std::vector<uint32_t> outputInterfaces);
+
+  Ipv4Address m_origin;
+  Ipv4Address m_group;
+  uint32_t m_inputInterface;
+  std::vector<uint32_t> m_outputInterfaces;
+};
+
+std::ostream& operator<< (std::ostream& os, Ipv4MulticastRoute const& route);
+
 }//namespace ns3
 
 #endif /* IPV4_ROUTE_H */
--- a/src/node/ipv4.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/node/ipv4.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -36,10 +36,10 @@
 {}
 
 uint32_t 
-GetIfIndexByIpv4Address (Ptr<Node> node, Ipv4Address a, Ipv4Mask amask)
+Ipv4::GetIfIndexByAddress (Ptr<Node> node, Ipv4Address a, Ipv4Mask amask)
 {
   Ptr<Ipv4> ipv4 = node->QueryInterface<Ipv4> (Ipv4::iid);
-  NS_ASSERT_MSG (ipv4, "GetIfIndexByIpv4Address:  No Ipv4 interface");
+  NS_ASSERT_MSG (ipv4, "Ipv4::GetIfIndexByAddress:  No Ipv4 interface");
   for (uint32_t i = 0; i < ipv4->GetNInterfaces (); i++)
     {
       if (ipv4->GetAddress (i).CombineMask(amask) == a.CombineMask(amask) )
@@ -48,17 +48,26 @@
         }
     }
   // Mapping not found
-  NS_ASSERT_MSG (false, "GetIfIndexByIpv4Address failed");
+  NS_ASSERT_MSG (false, "Ipv4::GetIfIndexByAddress failed");
   return 0;
 }
 
+//
+// XXX BUGBUG I don't think this is really the right approach here.  The call
+// to GetRoute () filters down into Ipv4L3Protocol where it translates into
+// a call into the Ipv4 static routing package.  This bypasses any other
+// routing packages.  At a minimum, the name is misleading.
+//
 bool 
-GetIpv4RouteToDestination (Ptr<Node> node, Ipv4Route& route, 
-                           Ipv4Address a, Ipv4Mask amask)
+Ipv4::GetRouteToDestination (
+  Ptr<Node> node, 
+  Ipv4Route& route, 
+  Ipv4Address a, 
+  Ipv4Mask amask)
 {
   Ipv4Route tempRoute;
   Ptr<Ipv4> ipv4 = node->QueryInterface<Ipv4> (Ipv4::iid);
-  NS_ASSERT_MSG (ipv4, "GetIpv4RouteToDestination:  No Ipv4 interface");
+  NS_ASSERT_MSG (ipv4, "Ipv4::GetRouteToDestination:  No Ipv4 interface");
   for (uint32_t i = 0; i < ipv4->GetNRoutes (); i++) 
     {
       tempRoute = ipv4->GetRoute (i);
@@ -83,5 +92,4 @@
   return false;
 }
 
-
 } // namespace ns3
--- a/src/node/ipv4.h	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/node/ipv4.h	Wed Sep 12 18:06:09 2007 +0100
@@ -71,6 +71,7 @@
   /**
    * \brief Asynchronously requests a route for a given packet and IP header
    *
+   * \param ifIndex The interface index on which the packet was received.
    * \param ipHeader IP header of the packet
    * \param packet packet that is being sent or forwarded
    * \param routeReply callback that will receive the route reply
@@ -100,9 +101,47 @@
    * immediately after the IP header, although most routing do not
    * insert any extra header.
    */
-  virtual bool RequestRoute (const Ipv4Header &ipHeader,
+  virtual bool RequestRoute (uint32_t ifIndex,
+                             const Ipv4Header &ipHeader,
                              Packet packet,
                              RouteReplyCallback routeReply) = 0;
+
+/**
+ * \brief Synchronously check to see if we can determine the interface index 
+ * that will be used if a packet is sent to this destination.
+ *
+ * This method addresses a problem in the IP stack where a destination address
+ * must be present and checksummed into the IP header before the actual 
+ * interface over which the packet is sent can be determined.  The answer is
+ * to implement a known and intentional cross-layer violation.  This is the
+ * endpoint of a call chain that started up quite high in the stack (sockets)
+ * and has found its way down to the Ipv4L3Protocol which is consulting the
+ * routing protocols for what they would do if presented with a packet of the
+ * given destination.
+ *
+ * Note that the a single interface index is returned.  This means that if
+ * the destination address is a multicast, and an explicit route is present
+ * that includeds multiple output interfaces, that route cannot be used.
+ * 
+ * If there are multiple paths out of the node, the resolution is performed
+ * by Ipv4L3Protocol::GetIfIndexforDestination which has access to more 
+ * contextual information that is useful for making a determination.
+ *
+ * \param destination The Ipv4Address if the destination of a hypothetical 
+ * packet.  This may be a multicast group address.
+ * \param ifIndex A reference to the interface index over which a packet
+ * sent to this destination would be sent.
+ * \return Returns true if a route is found to the destination that involves
+ * a single output interface index, otherwise false.
+ *
+ * \see Ipv4StaticRouting
+ * \see Ipv4RoutingProtocol
+ * \see Ipv4L3Protocol
+ */
+  virtual bool RequestIfIndex (Ipv4Address destination, 
+                              uint32_t& ifIndex) = 0;
+
+  static const uint32_t IF_INDEX_ANY = 0xffffffff;
 };
 
 /**
@@ -194,17 +233,69 @@
    * \returns the number of entries in the routing table.
    */
   virtual uint32_t GetNRoutes (void) = 0;
+
   /**
    * \param i index of route to return
    * \returns the route whose index is i
    */
   virtual Ipv4Route GetRoute (uint32_t i) = 0;
+
   /**
    * \param i index of route to remove from routing table.
    */
   virtual void RemoveRoute (uint32_t i) = 0;
+
+  /**
+   * \brief Add a static multicast route for a given multicast source and 
+   *        group.
+   *
+   * \param origin The Ipv4 address of the multicast source.
+   * \param group The multicast group address.
+   * \param inputInterface The interface index over which the packet arrived.
+   * \param outputInterfaces The list of output interface indices over which 
+   *        the packet should be sent (excluding the inputInterface).
+   */
+  virtual void AddMulticastRoute (Ipv4Address origin,
+                                  Ipv4Address group,
+                                  uint32_t inputInterface,
+                                  std::vector<uint32_t> outputInterfaces) = 0;
+  /**
+   * \brief Remove a static multicast route for a given multicast source and
+   *        group.
+   *
+   * \param origin The Ipv4 address of the multicast source.
+   * \param group The multicast group address.
+   * \param inputInterface The interface index over which the packet arrived.
+   */
+  virtual void RemoveMulticastRoute (Ipv4Address origin,
+                                     Ipv4Address group,
+                                     uint32_t inputInterface) = 0;
   
   /**
+   * \brief Set the default static multicast route.
+   *
+   * \param outputInterface The network output interface index over which 
+   *        packets without specific routes should be sent.
+   */
+  virtual void SetDefaultMulticastRoute (uint32_t outputInterface) = 0;
+
+  /**
+   * \returns the number of entries in the multicast routing table.
+   */
+  virtual uint32_t GetNMulticastRoutes (void) const = 0;
+
+  /**
+   * \param i index of route to return
+   * \returns the route whose index is i
+   */
+  virtual Ipv4MulticastRoute GetMulticastRoute (uint32_t i) const = 0;
+
+  /**
+   * \param i index of route to remove from routing table.
+   */
+  virtual void RemoveMulticastRoute (uint32_t i) = 0;
+
+  /**
    * \param device device to add to the list of ipv4 interfaces
    *        which can be used as output interfaces during packet forwarding.
    * \returns the index of the ipv4 interface added.
@@ -214,49 +305,120 @@
    * make sure that it is never used during packet forwarding.
    */
   virtual uint32_t AddInterface (Ptr<NetDevice> device) = 0;
+
   /**
    * \returns the number of interfaces added by the user.
    */
   virtual uint32_t GetNInterfaces (void) = 0;  
 
   /**
+   * \brief Find and return the interface ID of the interface that has been
+   *        assigned the specified IP address.
+   * \param addr The IP address assigned to the interface of interest.
+   * \returns The index of the ipv4 interface with the given address.
+   *
+   * Each IP interface has an IP address associated with it.  It is often 
+   * useful to search the list of interfaces for one that corresponds to 
+   * a known IP Address.  This call takes an IP address as a parameter and
+   * returns the interface index of the first interface that has been assigned
+   * that address.  If the address is not found, this function asserts.
+   */
+  virtual uint32_t FindInterfaceForAddr (Ipv4Address addr) const = 0;
+
+  /**
+   * \brief Find and return the interface ID of the interface that has been
+   *        assigned the specified (masked) IP address.
+   * \param addr The IP address assigned to the interface of interest.
+   * \param mask The address mask to be used in address matching.
+   * \returns The index of the ipv4 interface with the given address.
+   *
+   * Each IP interface has an IP address associated with it.  It is often 
+   * useful to search the list of interfaces for one that corresponds to 
+   * a known IP Address.  This call takes an IP address and an IP address
+   * mask as parameters and returns the interface index of the first interface
+   * that matches the masked IP address.
+   */
+  virtual uint32_t FindInterfaceForAddr (Ipv4Address addr, 
+    Ipv4Mask mask) const = 0;
+
+  /**
    * \param i index of ipv4 interface
    * \returns the NetDevice associated with the ipv4 interface index
    */
   virtual Ptr<NetDevice> GetNetDevice (uint32_t i) = 0;
 
   /**
+   * \brief Join a multicast group for a given multicast source and 
+   *        group.
+   *
+   * \param origin The Ipv4 address of the multicast source.
+   * \param group The multicast group address.
+   */
+  virtual void JoinMulticastGroup (Ipv4Address origin, Ipv4Address group) = 0;
+
+  /**
+   * \brief Leave a multicast group for a given multicast source and 
+   *        group.
+   *
+   * \param origin The Ipv4 address of the multicast source.
+   * \param group The multicast group address.
+   */
+  virtual void LeaveMulticastGroup (Ipv4Address origin, Ipv4Address group) = 0;
+
+  /**
    * \param i index of ipv4 interface
    * \param address address to associate to the underlying ipv4 interface
    */
   virtual void SetAddress (uint32_t i, Ipv4Address address) = 0;
+
   /**
    * \param i index of ipv4 interface
    * \param mask mask to associate to the underlying ipv4 interface
    */
   virtual void SetNetworkMask (uint32_t i, Ipv4Mask mask) = 0;
+
   /**
    * \param i index of ipv4 interface
    * \returns the mask associated to the underlying ipv4 interface
    */
   virtual Ipv4Mask GetNetworkMask (uint32_t i) const = 0;
+
   /**
    * \param i index of ipv4 interface
    * \returns the address associated to the underlying ipv4 interface
    */
   virtual Ipv4Address GetAddress (uint32_t i) const = 0;
+
+  /**
+   * \param destination The IP address of a hypothetical destination.
+   * \returns The IP address assigned to the interface that will be used
+   * if we were to send a packet to destination.
+   */
+  virtual Ipv4Address GetSourceAddress (Ipv4Address destination) const = 0;
+
+  /**
+   * \param destination The IP address of a hypothetical destination.
+   * \param ifIndex filled in with the interface index that will be used to
+   *        send a packet to the hypothetical destination.
+   * \returns True if a single interface can be identified, false otherwise.
+   */
+  virtual bool GetIfIndexForDestination (Ipv4Address dest,
+    uint32_t &ifIndex) const = 0;
+
   /**
    * \param i index of ipv4 interface
    * \returns the Maximum Transmission Unit (in bytes) associated
    *          to the underlying ipv4 interface
    */
   virtual uint16_t GetMtu (uint32_t i) const = 0;
+
   /**
    * \param i index of ipv4 interface
    * \returns true if the underlying interface is in the "up" state,
    *          false otherwise.
    */
   virtual bool IsUp (uint32_t i) const = 0;
+
   /**
    * \param i index of ipv4 interface
    * 
@@ -264,6 +426,7 @@
    * considered valid during ipv4 forwarding.
    */
   virtual void SetUp (uint32_t i) = 0;
+
   /**
    * \param i index of ipv4 interface
    *
@@ -271,21 +434,18 @@
    * ignored during ipv4 forwarding.
    */
   virtual void SetDown (uint32_t i) = 0;
-  
-};
 
 /**
  * Convenience functions (Doxygen still needed)
  *
  * Return the ifIndex corresponding to the Ipv4Address provided.
  */
-uint32_t GetIfIndexByIpv4Address (Ptr<Node> node, 
-                                  Ipv4Address a, 
-                                  Ipv4Mask amask = Ipv4Mask("255.255.255.255"));
+  static uint32_t GetIfIndexByAddress (Ptr<Node> node, Ipv4Address a, 
+    Ipv4Mask amask = Ipv4Mask("255.255.255.255"));
 
-bool GetIpv4RouteToDestination (Ptr<Node> node, Ipv4Route& route, 
-                                Ipv4Address a, 
-                                Ipv4Mask amask = Ipv4Mask("255.255.255.255"));
+  static bool GetRouteToDestination (Ptr<Node> node, Ipv4Route& route, 
+    Ipv4Address a, Ipv4Mask amask = Ipv4Mask("255.255.255.255"));
+};
 
 } // namespace ns3 
 
--- a/src/node/net-device.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/node/net-device.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -114,6 +114,7 @@
 {
   return m_isBroadcast;
 }
+
 Address const &
 NetDevice::GetBroadcast (void) const
 {
@@ -140,10 +141,27 @@
   return m_isMulticast;
 }
 
+Address 
+NetDevice::GetMulticast (void) const
+{
+  NS_ASSERT_MSG (m_isMulticast, "NetDevice::GetMulticast (): "
+    "Invalid operation when not IsMulticast ()");
+  return m_multicast;
+}
+
+Address
+NetDevice::MakeMulticastAddress(Ipv4Address multicastGroup) const
+{
+  NS_ASSERT_MSG (m_isMulticast, "NetDevice::GetMulticast (): "
+    "Invalid operation when not IsMulticast ()");
+  return m_multicast;
+}
+
 void
-NetDevice::EnableMulticast (void)
+NetDevice::EnableMulticast (Address multicast)
 {
   m_isMulticast = true;
+  m_multicast = multicast;
 }
 
 void
--- a/src/node/net-device.h	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/node/net-device.h	Wed Sep 12 18:06:09 2007 +0100
@@ -29,6 +29,7 @@
 #include "ns3/object.h"
 #include "ns3/ptr.h"
 #include "address.h"
+#include "ipv4-address.h"
 
 namespace ns3 {
 
@@ -130,10 +131,69 @@
    * not true.
    */
   Address const &GetBroadcast (void) const;
+
   /**
    * \return value of m_isMulticast flag
    */
   bool IsMulticast (void) const;
+
+  /**
+   * \brief Return the MAC multicast base address used when mapping multicast
+   * groups to MAC multicast addresses.
+   *
+   * Typically when one constructs a multicast MAC addresses, some bits from
+   * the IP multicast group are copied into a corresponding MAC multicast 
+   * group.  In EUI-48, for example, the low order 23 bits of the multicast
+   * group are copied to the MAC multicast group base address.
+   *
+   * This method allows access to the underlying MAC multicast group base 
+   * address.  It is expected that in most cases, a net device client will
+   * allow the net device to perform the actual construction of the multicast
+   * address.  Use of this method is discouraged unless you have a good reason
+   * to perform a custom mapping.  You should prefer 
+   * NetDevice::MakeMulticastAddress which will do the RFC-specified mapping
+   * for the net device in question.
+   *
+   * \return The multicast address supported by this net device.
+   *
+   * \warning Calling this method is invalid if IsMulticast returns not true.
+   * The method NS_ASSERTs if the device is not a multicast device.
+   * \see NetDevice::MakeMulticastAddress
+   */
+  Address GetMulticast (void) const;
+
+  /**
+   * \brief Make and return a MAC multicast address using the provided
+   *        multicast group
+   *
+   * RFC 1112 says that an Ipv4 host group address is mapped to an Ethernet 
+   * multicast address by placing the low-order 23-bits of the IP address into 
+   * the low-order 23 bits of the Ethernet multicast address 
+   * 01-00-5E-00-00-00 (hex).  Similar RFCs exist for Ipv6 and Eui64 mappings.
+   * This method performs the multicast address creation function appropriate
+   * to the underlying MAC address of the device.  This MAC address is
+   * encapsulated in an abstract Address to avoid dependencies on the exact
+   * MAC address format.
+   *
+   * A default imlementation of MakeMulticastAddress is provided, but this
+   * method simply NS_ASSERTS.  In the case of net devices that do not support
+   * multicast, clients are expected to test NetDevice::IsMulticast and avoid
+   * attempting to map multicast packets.  Subclasses of NetDevice that do
+   * support multicasting are expected to override this method and provide an
+   * implementation appropriate to the particular device.
+   *
+   * \param multicastGroup The IP address for the multicast group destination
+   * of the packet.
+   * \return The MAC multicast Address used to send packets to the provided
+   * multicast group.
+   *
+   * \warning Calling this method is invalid if IsMulticast returns not true.
+   * \see Ipv4Address
+   * \see Address
+   * \see NetDevice::IsMulticast
+   */
+  virtual Address MakeMulticastAddress (Ipv4Address multicastGroup) const;
+
   /**
    * \return value of m_isPointToPoint flag
    */
@@ -204,9 +264,10 @@
    */
   void DisableBroadcast (void);
   /**
-   * Set m_isMulticast flag to true
+   * Enable multicast support. This method should be
+   * called by subclasses from their constructor
    */
-  void EnableMulticast (void);
+  void EnableMulticast (Address multicast);
   /**
    * Set m_isMulticast flag to false
    */
@@ -286,6 +347,7 @@
   uint16_t      m_ifIndex;
   Address       m_address;
   Address       m_broadcast;
+  Address       m_multicast;
   uint16_t      m_mtu;
   bool          m_isUp;
   bool          m_isBroadcast;
--- a/src/routing/global-routing/candidate-queue.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/routing/global-routing/candidate-queue.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -1,5 +1,7 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
+ * Copyright 2007 University of Washington
+ * 
  * 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;
@@ -12,6 +14,8 @@
  * 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:  Craig Dowell (craigdo@ee.washington.edu)
  */
 
 #include "ns3/debug.h"
--- a/src/routing/global-routing/candidate-queue.h	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/routing/global-routing/candidate-queue.h	Wed Sep 12 18:06:09 2007 +0100
@@ -1,5 +1,7 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
+ * Copyright 2007 University of Washington
+ * 
  * 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;
@@ -12,6 +14,8 @@
  * 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:  Craig Dowell (craigdo@ee.washington.edu)
  */
 
 #ifndef CANDIDATE_QUEUE_H
--- a/src/routing/global-routing/global-route-manager-impl.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/routing/global-routing/global-route-manager-impl.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -1,5 +1,8 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
+ * Copyright 2007 University of Washington
+ * Copyright (C) 1999, 2000 Kunihiro Ishiguro, Toshiaki Takada
+ * 
  * 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;
@@ -12,6 +15,12 @@
  * 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
+ *
+ * Authors:  Craig Dowell (craigdo@ee.washington.edu)
+ *           Tom Henderson (tomhend@u.washington.edu)
+ * 
+ * Kunihiro Ishigura, Toshiaki Takada (GNU Zebra) are attributed authors
+ * of the quagga 0.99.7/src/ospfd/ospf_spf.c code which was ported here
  */
 
 #include <utility>
@@ -1143,7 +1152,7 @@
 // we're looking for.  If we find one, return the corresponding interface
 // index.
 //
-          return (GetIfIndexByIpv4Address (node, a, amask) );
+          return (Ipv4::GetIfIndexByAddress (node, a, amask) );
         }
     }
 //
--- a/src/routing/global-routing/global-route-manager-impl.h	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/routing/global-routing/global-route-manager-impl.h	Wed Sep 12 18:06:09 2007 +0100
@@ -1,5 +1,7 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
+ * Copyright 2007 University of Washington
+ * 
  * 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;
@@ -12,6 +14,9 @@
  * 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
+ *
+ * Authors:  Craig Dowell (craigdo@ee.washington.edu)
+ *           Tom Henderson (tomhend@u.washington.edu)
  */
 
 #ifndef GLOBAL_ROUTE_MANAGER_IMPL_H
--- a/src/routing/global-routing/global-route-manager.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/routing/global-routing/global-route-manager.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -1,5 +1,7 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
+ * Copyright 2007 University of Washington
+ * 
  * 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;
@@ -12,6 +14,9 @@
  * 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
+ *
+ * Authors:  Craig Dowell (craigdo@ee.washington.edu)
+ *           Tom Henderson (tomhend@u.washington.edu)
  */
 
 #include "ns3/assert.h"
--- a/src/routing/global-routing/global-route-manager.h	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/routing/global-routing/global-route-manager.h	Wed Sep 12 18:06:09 2007 +0100
@@ -1,5 +1,7 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
+ * Copyright 2007 University of Washington
+ * 
  * 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;
@@ -12,6 +14,9 @@
  * 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
+ *
+ * Authors:  Craig Dowell (craigdo@ee.washington.edu)
+ *           Tom Henderson (tomhend@u.washington.edu)
  */
 
 #ifndef GLOBAL_ROUTE_MANAGER_H
--- a/src/routing/global-routing/global-router-interface.cc	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/routing/global-routing/global-router-interface.cc	Wed Sep 12 18:06:09 2007 +0100
@@ -1,5 +1,7 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
+ * Copyright 2007 University of Washington
+ * 
  * 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;
@@ -12,6 +14,9 @@
  * 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
+ *
+ * Authors:  Craig Dowell (craigdo@ee.washington.edu)
+ *           Tom Henderson (tomhend@u.washington.edu)
  */
 
 #include "ns3/debug.h"
--- a/src/routing/global-routing/global-router-interface.h	Tue Sep 11 15:09:55 2007 +0100
+++ b/src/routing/global-routing/global-router-interface.h	Wed Sep 12 18:06:09 2007 +0100
@@ -1,5 +1,7 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
+ * Copyright 2007 University of Washington
+ * 
  * 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;
@@ -12,6 +14,9 @@
  * 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
+ *
+ * Authors:  Craig Dowell (craigdo@ee.washington.edu)
+ *           Tom Henderson (tomhend@u.washington.edu)
  */
 
 #ifndef GLOBAL_ROUTER_INTERFACE_H