merge
authorGustavo J. A. M. Carneiro <gjc@inescporto.pt>
Fri, 28 Sep 2007 11:59:46 +0100
changeset 1642 8d5707931bb4
parent 1641 ec156f2946a1 (current diff)
parent 1532 1f54822519c0 (diff)
child 1643 fcc7fe86037a
merge
SConstruct
build.py
doc/build-waf.txt
examples/simple-p2p.cc
examples/waf
samples/main-grid-topology.cc
samples/main-packet.cc
samples/waf
src/applications/onoff-application.cc
src/applications/onoff-application.h
src/applications/onoff/waf
src/applications/packet-sink/waf
src/applications/udp-echo/waf
src/applications/wscript
src/common/array-trace-resolver.h
src/common/callback-trace-source.cc
src/common/callback-trace-source.h
src/common/chunk.cc
src/common/chunk.h
src/common/composite-trace-resolver.cc
src/common/composite-trace-resolver.h
src/common/empty-trace-resolver.cc
src/common/empty-trace-resolver.h
src/common/fv-trace-source.h
src/common/header.cc
src/common/stream-tracer-test.cc
src/common/stream-tracer.h
src/common/sv-trace-source.h
src/common/terminal-trace-resolver.h
src/common/trace-context.cc
src/common/trace-context.h
src/common/trace-resolver.cc
src/common/trace-resolver.h
src/common/trace-root.cc
src/common/trace-root.h
src/common/trailer.cc
src/common/uv-trace-source.h
src/common/variable-tracer-test.cc
src/common/waf
src/core/assert.cc
src/core/default-value.cc
src/core/default-value.h
src/core/object.cc
src/core/ptr.h
src/core/random-variable-default-value.cc
src/core/type-name.cc
src/core/waf
src/devices/csma/waf
src/devices/p2p/p2p-channel.cc
src/devices/p2p/p2p-channel.h
src/devices/p2p/p2p-net-device.cc
src/devices/p2p/p2p-net-device.h
src/devices/p2p/p2p-topology.cc
src/devices/p2p/p2p-topology.h
src/devices/p2p/wscript
src/devices/point-to-point/waf
src/internet-node/arp-private.cc
src/internet-node/arp-private.h
src/internet-node/header-utils.cc
src/internet-node/header-utils.h
src/internet-node/ipv4-private.cc
src/internet-node/ipv4-private.h
src/internet-node/l3-demux.cc
src/internet-node/l3-demux.h
src/internet-node/l3-protocol.cc
src/internet-node/l3-protocol.h
src/internet-node/waf
src/mobility/grid-topology.cc
src/mobility/grid-topology.h
src/mobility/hierarchical-mobility-model.cc
src/mobility/hierarchical-mobility-model.h
src/mobility/mobility-model-notifier.cc
src/mobility/mobility-model-notifier.h
src/mobility/mobility-model.cc
src/mobility/mobility-model.h
src/mobility/mobility.h
src/mobility/position.cc
src/mobility/position.h
src/mobility/random-position.cc
src/mobility/random-position.h
src/mobility/random-topology.cc
src/mobility/random-topology.h
src/mobility/rectangle-default-value.cc
src/mobility/rectangle-default-value.h
src/mobility/rectangle.cc
src/mobility/rectangle.h
src/mobility/speed.cc
src/mobility/speed.h
src/mobility/static-mobility-model.cc
src/mobility/static-mobility-model.h
src/mobility/static-speed-helper.cc
src/mobility/static-speed-helper.h
src/mobility/static-speed-mobility-model.cc
src/mobility/static-speed-mobility-model.h
src/mobility/waf
src/mobility/wscript
src/node/mac-address.cc
src/node/mac-address.h
src/node/waf
src/routing/global-routing/waf
src/simulator/event-id.cc
src/simulator/event-id.h
src/simulator/scheduler.h
src/simulator/simulator.cc
src/simulator/simulator.h
src/simulator/time-default-value.h
src/simulator/waf
tutorial/waf
utils/waf
waf
--- a/.hgignore	Thu Jul 19 13:17:35 2007 +0200
+++ b/.hgignore	Fri Sep 28 11:59:46 2007 +0100
@@ -1,9 +1,10 @@
-.*.orig$
-.*\.o$
-.*~$
-build-dir
-build
-.*\.sconsign
-doc/html.*
-doc/latex.*
-.lock-wscript
+\.rej$
+\.orig$
+\.o$
+~$
+^build-dir
+^build
+^doc/html
+^doc/latex
+^\.lock-wscript
+^\.waf
--- a/.hgtags	Thu Jul 19 13:17:35 2007 +0200
+++ b/.hgtags	Fri Sep 28 11:59:46 2007 +0100
@@ -1,3 +1,8 @@
 56928998e05c9c11f5f3aefe79be8d2843e0db88 release ns-3.0.1
 7ac5a4b0969b255c4824c926c2b37ef450136ce9 release ns-3.0.2
+0dc81e76166c56aaae64da48b673b62155943aad packet-history-working
 38099dd26e9467b8f49f8632f22789858149a6e7 release ns-3.0.3
+5701e60bf01a8ac1308945e69001e0cc07948faf release ns-3.0.4
+08046b6aef37932507696a2f2f427b42d693781e release ns-3.0.5
+267e2ebc28e4e4ae2f579e1cfc29902acade0c34 buffer-working-before-breaking
+606df29888e7573b825fc891a002f0757166b616 release ns-3.0.6
--- a/AUTHORS	Thu Jul 19 13:17:35 2007 +0200
+++ b/AUTHORS	Fri Sep 28 11:59:46 2007 +0100
@@ -3,4 +3,5 @@
 Craig Dowell (craigdo@ee.washington.edu)
 Tom Henderson (tomhend@u.washington.edu)
 Mathieu Lacage (mathieu.lacage@sophia.inria.fr)
+Emmanuelle Laprise (emmmanuelle.laprise@bluekazoo.ca)
 George F. Riley (riley@ece.gatech.edu)
--- a/README	Thu Jul 19 13:17:35 2007 +0200
+++ b/README	Fri Sep 28 11:59:46 2007 +0100
@@ -71,17 +71,13 @@
 
 To build the set of default libraries and the example
 programs included in this package, you need to use the
-tool 'scons'. Detailed information on how to install
-and use scons is included in the file doc/build.txt
+tool 'waf'. Detailed information on how to install
+and use waf is included in the file doc/build.txt
 
 However, the real quick and dirty way to get started is to
-type the command "scons" the the directory which contains
+type the command "./waf" the the directory which contains
 this README file. The files built will be copied in the
-build-dir/dbg-shared/bin and build-dir/dbg-shared/lib
-directories. build-dir/dbg-shared/bin will contain
-one binary for each of the sample code in the 'samples'
-directory and one binary for each of the detailed examples
-found in the 'examples' directory.
+build/debug or build/optimized.
 
 The current codebase is expected to build and run on the
 following set of platforms:
@@ -106,12 +102,7 @@
 should be easy to run the sample programs with the
 following command:
 
-./build-dir/dbg-shared/bin/simple-p2p
-
-or:
-
-cd build-dir/dbg-shared/bin
-./simple-p2p
+./waf --run simple-p2p
 
 That program should generate a simple-p2p.tr text 
 trace file and a set of simple-p2p-xx-xx.pcap binary
@@ -152,7 +143,7 @@
     file in http://code.nsnam.org/docs
 
   - the doxygen documentation is generated from the doc/doxygen.conf
-    configuration file. The command "scons doc" will generate it
+    configuration file. The command "./waf --doxygen" will generate it
     as doc/html/index.html if you have installed the doxygen tools 
     (see http://www.doxygen.org)
 
--- a/RELEASE_NOTES	Thu Jul 19 13:17:35 2007 +0200
+++ b/RELEASE_NOTES	Fri Sep 28 11:59:46 2007 +0100
@@ -3,6 +3,32 @@
 
 This file contains ns-3 release notes (most recent releases first).
 
+Release 3.0.6 (2007/09/15)
+========================
+  - Static multicast IPv4 routing
+  - Logging overhaul (NS_LOG macros)
+  - Refactoring of tracing subsystem
+  - Tutorial document started
+ 
+Release 3.0.5 (2007/08/15)
+========================
+
+  - Refactoring to support win32-based unix environments (Cygwin, mingw)
+  - "Packet socket" for allowing applications to access NetDevices directly
+  - Generalized, polymorphic Address class
+  - Add CSMA NetDevice model (from Emmanuelle Laprise)
+  - Modularize IPv4 routing support (from Gustavo Carneiro)
+  - Add mobility framework and basic mobility models 
+  - Global unicast centralized routing 
+
+Release 3.0.4 (2007/07/15)
+========================
+
+  - Enable waf as the default build system.
+  - Per-packet metadata:  a system to track which headers and trailers 
+    are added to a packet
+  - Simplifications to point-to-point devices and channel
+
 Release 3.0.3 (2007/06/15)
 ========================
 
--- a/SConstruct	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,542 +0,0 @@
-## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
-import os.path
-import build
-
-version_file = open ('VERSION', 'r')
-version = version_file.readline ()
-version_file.close ()
-version = version.strip ()
-
-ns3 = build.Ns3()
-ns3.build_dir = 'build-dir'
-ns3.version = version
-ns3.name = 'ns3'
-ns3.distname = 'ns'
-ns3.doxygen_config = os.path.join('doc', 'doxygen.conf')
-ns3.add_extra_dist(os.path.join('doc', 'main.txt'))
-ns3.add_extra_dist ('doc/architecture.pdf')
-ns3.add_extra_dist ('doc/contributing.txt')
-ns3.add_extra_dist ('doc/build.txt')
-ns3.add_extra_dist ('doc/codingstd.txt')
-ns3.add_extra_dist ('doc/mercurial.txt')
-ns3.add_extra_dist ('README')
-ns3.add_extra_dist ('RELEASE_NOTES')
-ns3.add_extra_dist ('AUTHORS')
-ns3.add_extra_dist ('VERSION')
-
-ns3.add_extra_dist('doc/build-waf.txt')
-ns3.add_extra_dist('ns3/_placeholder_')
-for wscript in [
-    "src/core/wscript",
-    "src/node/wscript",
-    "src/devices/p2p/wscript",
-    "src/common/wscript",
-    "src/applications/wscript",
-    "src/simulator/wscript",
-    "src/internet-node/wscript",
-    "src/wscript",
-    "utils/wscript",
-    "samples/wscript",
-    "examples/wscript",
-    "wscript",
-    ]:
-    ns3.add_extra_dist(wscript)
-ns3.add_extra_dist('waf')
-ns3.add_extra_dist('waf.bat')
-
-
-
-#
-# The Core module
-#
-core = build.Ns3Module('core', 'src/core')
-ns3.add(core)
-core.add_sources([
-    'callback-test.cc',
-    'debug.cc',
-    'assert.cc',
-    'ptr.cc',
-    'object.cc',
-    'test.cc',
-    'random-variable.cc',
-    'rng-stream.cc',
-    'uid-manager.cc',
-    'default-value.cc',
-    'random-variable-default-value.cc',
-    'command-line.cc',
-    'type-name.cc',
-    'component-manager.cc',
-    ])
-env = Environment()
-if env['PLATFORM'] == 'posix' or env['PLATFORM'] == 'darwin' or env['PLATFORM'] == 'cygwin':
-    core.add_external_dep('pthread')
-    core.add_sources([
-        'unix-system-wall-clock-ms.cc',
-        ])
-elif env['PLATFORM'] == 'win32':
-    core.add_sources([
-        'win32-system-wall-clock-ms.cc',
-        ])
-core.add_headers ([
-    'uid-manager.h',
-    'singleton.h',
-])
-core.add_inst_headers([
-    'system-wall-clock-ms.h',
-    'empty.h',
-    'callback.h',
-    'ptr.h',
-    'object.h',
-    'debug.h',
-    'assert.h',
-    'fatal-error.h',
-    'test.h',
-    'random-variable.h',
-    'rng-stream.h',
-    'default-value.h',
-    'random-variable-default-value.h',
-    'command-line.h',
-    'type-name.h',
-    'component-manager.h',
-    ])
-
-def config_core (env, config):
-    retval = []
-    # XXX This check is primitive but it should be
-    # good enough for now.
-    if config.CheckCHeader ('stdlib.h') == 1:
-        retval.append ('#define HAVE_STDLIB_H 1')
-        retval.append ('#define HAVE_GETENV 1')
-    else:
-        retval.append ('#undef HAVE_STDLIB_H')
-        retval.append ('#undef HAVE_GETENV')
-    return retval
-core.add_config (config_core)
-
-#
-# The Simu module
-#
-simu = build.Ns3Module('simulator', 'src/simulator')
-ns3.add(simu)
-simu.add_dep('core')
-simu.add_external_dep('m')
-simu.add_sources([
-    'high-precision.cc',
-    'time.cc',
-    'event-id.cc',
-    'scheduler.cc',
-    'scheduler-factory.cc',
-    'scheduler-list.cc',
-    'scheduler-heap.cc',
-    'scheduler-map.cc',
-    'event-impl.cc',
-    'simulator.cc',
-    'time-default-value.cc',
-    ])
-simu.add_headers([
-    'scheduler-heap.h',
-    'scheduler-map.h',
-    'scheduler-list.h'
-    ])
-simu.add_inst_headers([
-    'high-precision.h',
-    'nstime.h',
-    'event-id.h',
-    'event-impl.h',
-    'simulator.h',
-    'scheduler.h',
-    'scheduler-factory.h',
-    'simulation-singleton.h',
-    'time-default-value.h',
-    ])
-high_precision_as_double = ARGUMENTS.get('high-precision-as-double', 'n')
-if high_precision_as_double == 'y':
-    simu.add_inst_header ('high-precision-double.h')
-    simu.add_source ('high-precision-double.cc')
-else:
-    simu.add_inst_headers ([
-        'high-precision-128.h',
-        'cairo-wideint-private.h'
-        ])
-    simu.add_sources ([
-        'high-precision-128.cc',
-        'cairo-wideint.c',
-        ])
-
-def config_simulator (env, config):
-    retval = []
-    high_precision_as_double = ARGUMENTS.get('high-precision-as-double', 'n')
-    if high_precision_as_double == 'y':
-        retval.append ('#define USE_HIGH_PRECISION_DOUBLE 1')
-    else:
-        retval.append ('#undef USE_HIGH_PRECISION_DOUBLE')
-    if config.CheckCHeader ('stdint.h') == 1:
-        retval.append ('#define HAVE_STDINT_H 1')
-    elif config.CheckCHeader ('inttypes.h') == 1:
-        retval.append ('#define HAVE_INTTYPES_H 1')
-    elif config.CheckCHeader ('sys/inttypes.h') == 1:
-        retval.append ('#define HAVE_SYS_INT_TYPES_H 1')
-    return retval
-simu.add_config (config_simulator)
-    
-
-#
-# The Common module
-#
-common = build.Ns3Module('common', 'src/common')
-common.add_deps(['core', 'simulator'])
-ns3.add(common)
-common.add_sources([
-    'buffer.cc',
-    'chunk.cc',
-    'header.cc',
-    'trailer.cc',
-    'packet.cc',
-    'tags.cc',
-    'pcap-writer.cc',
-    'variable-tracer-test.cc',
-    'trace-context.cc',
-    'trace-resolver.cc',
-    'callback-trace-source.cc',
-    'empty-trace-resolver.cc',
-    'composite-trace-resolver.cc',
-    'trace-root.cc',
-    'data-rate.cc',
-    ])
-common.add_headers ([
-    ])
-common.add_inst_headers([
-    'buffer.h',
-    'chunk.h',
-    'header.h',
-    'trailer.h',
-    'tags.h',
-    'packet.h',
-    'uv-trace-source.h',
-    'sv-trace-source.h',
-    'fv-trace-source.h',
-    'pcap-writer.h',
-    'callback-trace-source.h',
-    'trace-context.h',
-    'trace-resolver.h',
-    'empty-trace-resolver.h',
-    'composite-trace-resolver.h',
-    'array-trace-resolver.h',
-    'trace-root.h',
-    'terminal-trace-resolver.h',
-    'data-rate.h',
-    ])
-
-mobility = build.Ns3Module ('mobility', 'src/mobility');
-ns3.add (mobility);
-mobility.add_deps (['core', 'simulator', 'node'])
-mobility.add_sources ([
-    'position.cc',
-    'speed.cc',
-    'random-position.cc',
-    'rectangle-default-value.cc',
-    'rectangle.cc',
-    'mobility-model.cc',
-    'mobility-model-notifier.cc',
-    'static-speed-helper.cc',
-    'static-mobility-model.cc',
-    'static-speed-mobility-model.cc',
-    'hierarchical-mobility-model.cc',
-    'random-direction-2d-mobility-model.cc',
-    'random-waypoint-mobility-model.cc',
-    'random-walk-2d-mobility-model.cc',
-    'grid-topology.cc',
-    'random-topology.cc',
-    'ns2-mobility-file-topology.cc',
-    ])
-mobility.add_inst_headers ([
-    'position.h',
-    'speed.h',
-    'random-position.h',
-    'rectangle-default-value.h',
-    'rectangle.h',
-    'mobility-model.h',
-    'mobility-model-notifier.h',
-    'static-speed-helper.h',
-    'static-mobility-model.h',
-    'static-speed-mobility-model.h',
-    'hierarchical-mobility-model.h',
-    'random-direction-2d-mobility-model.h',
-    'random-waypoint-mobility-model.h',
-    'random-walk-2d-mobility-model.h',
-    'grid-topology.h',
-    'random-topology.h',
-    'ns2-mobility-file-topology.h',
-    ])
-mobility.add_headers ([
-    'mobility.h'
-    ])
-
-node = build.Ns3Module ('node', 'src/node')
-ns3.add (node)
-node.add_deps (['core', 'common', 'simulator'])
-node.add_sources ([
-    'node.cc',
-    'ipv4-address.cc',
-    'net-device.cc',
-    'mac-address.cc',
-    'llc-snap-header.cc',
-    'ipv4-route.cc',
-    'queue.cc',
-    'drop-tail-queue.cc',
-    'channel.cc',
-    'node-list.cc',
-    'socket.cc',
-    'socket-factory.cc',
-    'udp.cc',
-    'ipv4.cc',
-    'application.cc',
-    ])
-node.add_inst_headers ([
-    'node.h',
-    'ipv4-address.h',
-    'net-device.h',
-    'mac-address.h',
-    'ipv4-route.h',
-    'queue.h',
-    'drop-tail-queue.h',
-    'llc-snap-header.h',
-    'channel.h',
-    'node-list.h',
-    'socket.h',
-    'socket-factory.h',
-    'udp.h',
-    'ipv4.h',
-    'application.h',
-    ])
-
-applications = build.Ns3Module ('applications', 'src/applications')
-ns3.add (applications)
-applications.add_deps (['node'])
-applications.add_sources ([
-    'onoff-application.cc',
-])
-applications.add_inst_headers ([
-    'onoff-application.h',
-])
-
-inode = build.Ns3Module ('internet-node', 'src/internet-node')
-ns3.add (inode)
-inode.add_deps (['node'])
-inode.add_sources ([
-    'internet-node.cc',
-    'l3-demux.cc',
-    'l3-protocol.cc',
-    'ipv4-l4-demux.cc',
-    'ipv4-l4-protocol.cc',
-    'ipv4-header.cc',
-    'udp-header.cc',
-    'ipv4-checksum.cc',
-    'ipv4-interface.cc',
-    'ipv4-l3-protocol.cc',
-    'ipv4-end-point.cc',
-    'udp-l4-protocol.cc',
-    'arp-header.cc',
-    'arp-cache.cc',
-    'arp-ipv4-interface.cc',
-    'arp-l3-protocol.cc',
-    'ipv4-loopback-interface.cc',
-    'header-utils.cc',
-    'udp-socket.cc',
-    'ipv4-end-point-demux.cc',
-    'arp-private.cc',
-    'ipv4-impl.cc',
-    'ipv4-private.cc',
-    'ascii-trace.cc',
-    'pcap-trace.cc',
-    'udp-impl.cc',
-])
-inode.add_headers ([
-    'ipv4-header.h',
-    'udp-header.h',
-    'ipv4-checksum.h',
-    'arp-header.h',
-    'arp-cache.h',
-    'arp-l3-protocol.h',
-    'ipv4-loopback-interface.h',
-    'l3-demux.h',
-    'header-utils.h',
-    'arp-ipv4-interface.h',
-    'udp-socket.h',
-    'udp-l4-protocol.h',
-    'arp-private.h',
-    'ipv4-impl.h',
-    'ipv4-private.h',
-    'ipv4-l3-protocol.h',
-    'l3-protocol.h',
-    'ipv4-l4-protocol.h',
-    'ipv4-l4-demux.h',
-    'ipv4-end-point-demux.h',
-    'ipv4-end-point.h',
-    'ipv4-header.h',
-    'udp-header.h',
-    'ipv4-interface.h',
-    'sgi-hashmap.h',
-    'udp-impl.h',
-])
-inode.add_inst_headers ([
-    'internet-node.h',
-    'ascii-trace.h',
-    'pcap-trace.h',
-])
-
-
-
-p2p = build.Ns3Module ('p2p', 'src/devices/p2p')
-ns3.add (p2p)
-p2p.add_deps (['node'])
-p2p.add_sources ([
-    'p2p-net-device.cc',
-    'p2p-channel.cc',
-    'p2p-topology.cc',
-    ])
-p2p.add_inst_headers ([
-    'p2p-net-device.h',
-    'p2p-channel.h',
-    'p2p-topology.h',
-    ])
-
-
-# utils
-mobgen = build.Ns3Module ('mobility-generator', 'utils')
-ns3.add (mobgen)
-mobgen.set_executable ()
-mobgen.add_deps (['simulator', 'node', 'mobility'])
-mobgen.add_source ('mobility-generator.cc')
-
-run_tests = build.Ns3Module('run-tests', 'utils')
-ns3.add(run_tests)
-run_tests.set_executable()
-run_tests.add_deps(['core', 'simulator', 'common'])
-run_tests.add_source('run-tests.cc')
-
-bench_object = build.Ns3Module('bench-object', 'utils')
-ns3.add(bench_object)
-bench_object.set_executable()
-bench_object.add_deps(['core'])
-bench_object.add_source('bench-object.cc')
-
-bench_packets = build.Ns3Module('bench-packets', 'utils')
-#ns3.add(bench_packets)
-bench_packets.set_executable()
-bench_packets.add_dep('core')
-bench_packets.add_source('bench-packets.cc')
-
-bench_simu = build.Ns3Module('bench-simulator', 'utils')
-ns3.add(bench_simu)
-bench_simu.set_executable()
-bench_simu.add_dep('simulator')
-bench_simu.add_source('bench-simulator.cc')
-
-replay_simu = build.Ns3Module('replay-simulation', 'utils')
-ns3.add(replay_simu)
-replay_simu.set_executable()
-replay_simu.add_dep('simulator')
-replay_simu.add_source('replay-simulation.cc')
-
-
-# samples
-sample_debug = build.Ns3Module('sample-debug', 'samples')
-sample_debug.set_executable()
-ns3.add(sample_debug)
-sample_debug.add_dep('core')
-sample_debug.add_source('main-debug.cc')
-sample_debug.add_source('main-debug-other.cc')
-
-sample_callback = build.Ns3Module('sample-callback', 'samples')
-sample_callback.set_executable()
-ns3.add(sample_callback)
-sample_callback.add_dep('core')
-sample_callback.add_source('main-callback.cc')
-
-sample_random_walk = build.Ns3Module('sample-random-walk', 'samples')
-sample_random_walk.set_executable()
-ns3.add(sample_random_walk)
-sample_random_walk.add_deps(['core', 'mobility'])
-sample_random_walk.add_source('main-random-walk.cc')
-
-sample_grid_topology = build.Ns3Module('sample-grid-topology', 'samples')
-sample_grid_topology.set_executable()
-ns3.add(sample_grid_topology)
-sample_grid_topology.add_deps(['core', 'internet-node', 'mobility'])
-sample_grid_topology.add_source('main-grid-topology.cc')
-
-sample_ptr = build.Ns3Module('sample-ptr', 'samples')
-sample_ptr.set_executable()
-ns3.add(sample_ptr)
-sample_ptr.add_dep('core')
-sample_ptr.add_source('main-ptr.cc')
-
-sample_trace = build.Ns3Module('sample-trace', 'samples')
-#ns3.add(sample_trace)
-sample_trace.add_dep('common')
-sample_trace.set_executable()
-sample_trace.add_source('main-trace.cc')
-
-sample_query_interface = build.Ns3Module('sample-query-interface', 'samples')
-ns3.add(sample_query_interface)
-sample_query_interface.add_dep('common')
-sample_query_interface.set_executable()
-sample_query_interface.add_source('main-query-interface.cc')
-
-sample_simu = build.Ns3Module('sample-simulator', 'samples')
-ns3.add(sample_simu)
-sample_simu.set_executable()
-sample_simu.add_dep('simulator')
-sample_simu.add_source('main-simulator.cc')
-
-sample_packet = build.Ns3Module('sample-packet', 'samples')
-ns3.add(sample_packet)
-sample_packet.set_executable()
-sample_packet.add_dep('common')
-sample_packet.add_source('main-packet.cc')
-
-sample_test = build.Ns3Module('sample-test', 'samples')
-sample_test.set_executable()
-ns3.add(sample_test)
-sample_test.add_dep('core')
-sample_test.add_source('main-test.cc')
-
-sample_simple = build.Ns3Module('sample-simple', 'samples')
-sample_simple.set_executable()
-ns3.add(sample_simple)
-sample_simple.add_deps(['core', 'simulator', 'node', 'internet-node'])
-sample_simple.add_source('main-simple.cc')
-
-sample_sp2p = build.Ns3Module('sample-simple-p2p', 'samples')
-sample_sp2p.set_executable()
-#n3.add(sample_sp2p)
-sample_sp2p.add_deps(['core', 'simulator', 'node', 'internet-node', 'p2p'])
-sample_sp2p.add_source('main-simple-p2p.cc')
-
-sample_default_value = build.Ns3Module('sample-default-value', 'samples')
-sample_default_value.set_executable()
-ns3.add(sample_default_value)
-sample_default_value.add_deps(['core', 'simulator', 'node', 'p2p'])
-sample_default_value.add_source('main-default-value.cc')
-
-sample_object = build.Ns3Module('sample-object', 'samples')
-sample_object.set_executable()
-ns3.add(sample_object)
-sample_object.add_deps(['core'])
-sample_object.add_source('main-object.cc')
-
-sample_component_manager = build.Ns3Module('sample-component-manager', 'samples')
-sample_component_manager.set_executable()
-ns3.add(sample_component_manager)
-sample_component_manager.add_deps(['core'])
-sample_component_manager.add_source('main-component-manager.cc')
-
-# examples
-example_simple_p2p = build.Ns3Module('simple-p2p', 'examples')
-example_simple_p2p.set_executable()
-ns3.add(example_simple_p2p)
-example_simple_p2p.add_deps(['core', 'simulator', 'node', 'p2p', 'internet-node', 'applications'])
-example_simple_p2p.add_source('simple-p2p.cc')
-
-ns3.generate_dependencies()
--- a/VERSION	Thu Jul 19 13:17:35 2007 +0200
+++ b/VERSION	Fri Sep 28 11:59:46 2007 +0100
@@ -1,1 +1,1 @@
-3.0.3
+3.0.6
--- a/build.py	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,561 +0,0 @@
-## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
-# Copyright (c) 2006 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
-# 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>
-
-
-
-import os
-import os.path
-import shutil
-from SCons.Environment import Environment
-from SCons.Builder import Builder
-from SCons.Action import Action
-import SCons
-
-# hack stolen from wengo
-# to get an ARGUMENTS defined correctly
-try:
-    ARGUMENTS = SCons.Script.ARGUMENTS
-    COMMAND_LINE_TARGETS = SCons.Script.COMMAND_LINE_TARGETS
-except AttributeError:
-    from SCons.Script.SConscript import Arguments
-    from SCons.Script.SConscript import CommandLineTargets
-    ARGUMENTS = Arguments
-    COMMAND_LINE_TARGETS = CommandLineTargets
-
-class Ns3Module:
-    def __init__(self, name, dir):
-        self.sources = []
-        self.inst_headers = []
-        self.headers = []
-        self.extra_dist = []
-        self.deps = []
-        self.external_deps = []
-        self.config = []
-        self.name = name
-        self.dir = dir
-        self.executable = False
-        self.library = True
-        self.ldflags = []
-        self.header_inst_dir = ''
-    def set_library(self):
-        self.library = True
-        self.executable = False
-    def set_executable(self):
-        self.library = False
-        self.executable = True
-    def add_config(self, config_fn):
-        self.config.append(config_fn)
-    def add_extra_dist(self, dist):
-        self.extra_dist.append(dist)
-    def add_external_dep(self, dep):
-        self.external_deps.append(dep)
-    def add_dep(self, dep):
-        self.deps.append(dep)
-    def add_deps(self, deps):
-        self.deps.extend(deps)
-    def add_source(self, source):
-        self.sources.append(source)
-    def add_sources(self, sources):
-        self.sources.extend(sources)
-    def add_header(self, header):
-        self.headers.append(header)
-    def add_headers(self, headers):
-        self.headers.extend(headers)
-    def add_inst_header(self, header):
-        self.inst_headers.append(header)
-    def add_inst_headers(self, headers):
-        self.inst_headers.extend(headers)
-    def add_ldflags (self, ldflags):
-        self.ldflags.extend (ldflags)
-    def add_ldflag (self, ldflag):
-        self.add_ldflags ([ldflag])
-    def set_header_inst_dir (self, inst_dir):
-        self.header_inst_dir = inst_dir
-        
-
-def MyCopyAction(target, source, env):
-    try:
-        if len(target) == len(source):
-            for i in range(len(target)):
-                shutil.copy(source[i].path, target[i].path)
-            return 0
-        else:
-            return 'invalid target/source match'
-    except:
-        print
-        return 'exception'
-def MyCopyActionPrint(target, source, env):
-    if len(target) == len(source):
-        output = ''
-        for i in range(len(target)):
-            output = output + 'copy \'' + source[i].path + '\' to \'' + target[i].path + '\''
-            if i < len(target) - 1:
-                output = output + '\n'
-        return output
-    else:
-        return 'error in copy'
-def GcxxEmitter(target, source, env):
-    if os.path.exists(source[0].path):
-        return [target, source]
-    else:
-        return [[], []]
-def MyRmTree(target, source, env):
-    shutil.rmtree(env['RM_DIR'])
-    return 0
-def MyRmTreePrint(target, source, env):
-    return ''
-def print_cmd_line(s, target, src, env):
-    print 'Building ' + (' and '.join([str(x) for x in target])) + '...'
-
-class Ns3BuildVariant:
-    def __init__(self):
-        self.static = False
-        self.gcxx_deps = False
-        self.gcxx_root = ''
-        self.build_root = ''
-        self.env = None
-
-class Ns3:
-    def __init__(self):
-        self.__modules = []
-        self.extra_dist = []
-        self.build_dir = 'build'
-        self.version = '0.0.1'
-        self.name = 'noname'
-        self.distname = 'noname'
-        self.doxygen_config = ''
-    def add(self, module):
-        self.__modules.append(module)
-    def add_extra_dist(self, dist):
-        self.extra_dist.append(dist)
-    def __get_module(self, name):
-        for module in self.__modules:
-            if module.name == name:
-                return module
-        return None
-    def get_mod_output(self, module, variant):
-        if module.executable:
-            suffix = variant.env.subst(variant.env['PROGSUFFIX'])
-            filename = os.path.join(variant.build_root, 'bin', 
-                                    module.name + suffix)
-        else:
-            if variant.static:
-                prefix = variant.env['LIBPREFIX']
-                suffix = variant.env['LIBSUFFIX']
-            else:
-                prefix = variant.env['SHLIBPREFIX']
-                suffix = variant.env['SHLIBSUFFIX']
-            prefix = variant.env.subst(prefix)
-            suffix = variant.env.subst(suffix)
-            filename = os.path.join(variant.build_root, 'lib', 
-                                     prefix + module.name + suffix)
-        return filename
-    def get_obj_builders(self, variant, module):
-        env = variant.env.Copy ()
-        objects = []
-        hash = {}
-        self.get_internal_deps (module, hash)
-        for dep in hash.values ():
-            if dep.header_inst_dir != '':
-                inc_dir = os.path.join(variant.build_root, 'include', 
-                                       self.name, dep.header_inst_dir)
-                env.Append (CPPPATH = [inc_dir])
-                
-        if len(module.config) > 0:
-            src_config_file = os.path.join(self.build_dir, 'config', module.name + '-config.h')
-            tgt_config_file = os.path.join(variant.build_root, 'include', 
-                                           self.name, module.name + '-config.h')
-
-        for source in module.sources:
-            obj_file = os.path.splitext(source)[0] + '.o'
-            tgt = os.path.join(variant.build_root, module.dir, obj_file)
-            src = os.path.join(module.dir, source)
-            if variant.static:
-                obj_builder = env.StaticObject(target = tgt, source = src)
-            else:
-                obj_builder = env.SharedObject(target = tgt, source = src)
-            if len(module.config) > 0:
-                config_file = env.MyCopyBuilder(target = [tgt_config_file], 
-                                                    source = [src_config_file])
-                env.Depends(obj_builder, config_file)
-            if variant.gcxx_deps:
-                gcno_tgt = os.path.join(variant.build_root, module.dir, 
-                                        os.path.splitext(source)[0] + '.gcno')
-                gcda_tgt = os.path.join(variant.build_root, module.dir, 
-                                        os.path.splitext(source)[0] + '.gcda')
-                gcda_src = os.path.join(variant.gcxx_root, module.dir, 
-                                        os.path.splitext(source)[0] + '.gcda')
-                gcno_src = os.path.join(variant.gcxx_root, module.dir, 
-                                        os.path.splitext(source)[0] + '.gcno')
-                gcno_builder = env.CopyGcxxBuilder(target = gcno_tgt, source = gcno_src)
-                gcda_builder = env.CopyGcxxBuilder(target = gcda_tgt, source = gcda_src)
-                env.Depends(obj_builder, gcda_builder)
-                env.Depends(obj_builder, gcno_builder)
-            objects.append(obj_builder)
-        return objects
-    def get_internal_deps(self, module, hash):
-        for dep_name in module.deps:
-            dep = self.__get_module(dep_name)
-            hash[dep_name] = dep
-            self.get_internal_deps(dep, hash)
-    def get_external_deps(self, module):
-        hash = {}
-        self.get_internal_deps(module, hash)
-        ext_hash = {}
-        for mod in hash.values():
-            for ext_dep in mod.external_deps:
-                ext_hash[ext_dep] = 1
-        return ext_hash.keys()
-    def get_sorted_deps(self, module):
-        h = {}
-        self.get_internal_deps(module, h)
-        modules = []
-        for dep in h.keys():
-            deps_copy = []
-            mod = h[dep]
-            deps_copy.extend(mod.deps)
-            modules.append([mod, deps_copy])
-        sorted = []
-        while len(modules) > 0:
-            to_remove = []
-            for item in modules:
-                if len(item[1]) == 0:
-                    to_remove.append(item[0].name)
-            for item in to_remove:
-                for i in modules:
-                    if item in i[1]:
-                        i[1].remove(item)
-            new_modules = []
-            for mod in modules:
-                found = False
-                for i in to_remove:
-                    if i == mod[0].name:
-                        found = True
-                        break
-                if not found:
-                    new_modules.append(mod)
-            modules = new_modules
-            sorted.extend(to_remove)
-        sorted.reverse()
-        # append external deps
-        ext_deps = self.get_external_deps(module)
-        for dep in ext_deps:
-            sorted.append(dep)
-        return sorted
-
-    def gen_mod_dep(self, variant):
-        build_root = variant.build_root
-        cpp_path = os.path.join(variant.build_root, 'include')
-        env = variant.env
-        env.Append(CPPPATH = [cpp_path])
-        header_dir = os.path.join(build_root, 'include', self.name)
-        lib_path = os.path.join(build_root, 'lib')
-        env.Append (LIBPATH = [lib_path])
-        module_builders = []
-        for module in self.__modules:
-            my_env = env.Copy ();
-            objects = self.get_obj_builders(variant, module)
-            libs = self.get_sorted_deps(module)
-            my_env.Append (LIBS = libs)
-            my_env.Append (LINKFLAGS = module.ldflags)
-
-            filename = self.get_mod_output(module, variant)
-            if module.executable:
-                module_builder = my_env.Program(target=filename, source=objects)
-            else:
-                if variant.static:
-                    module_builder = my_env.StaticLibrary(target=filename, source=objects)
-                else:
-                    module_builder = my_env.SharedLibrary(target=filename, source=objects)
-
-            for dep_name in module.deps:
-                dep = self.__get_module(dep_name)
-                my_env.Depends(module_builder, self.get_mod_output(dep, variant))
-
-            for header in module.inst_headers:
-                if module.header_inst_dir != '':
-                    tgt = os.path.join(header_dir, module.header_inst_dir, header)
-                else:
-                    tgt = os.path.join(header_dir, header)
-                src = os.path.join(module.dir, header)
-                #builder = env.Install(target = tgt, source = src)
-                header_builder = my_env.MyCopyBuilder(target=tgt, source=src)
-                my_env.Depends(module_builder, header_builder)
-
-            module_builders.append(module_builder)
-        return module_builders
-    def gen_mod_config(self, env):
-        config_dir = os.path.join(self.build_dir, 'config')
-        for module in self.__modules:
-            if len(module.config) > 0:
-                config_file = os.path.join(config_dir, module.name + '-config.h')
-                config_file_guard = module.name + '_CONFIG_H'
-                config_file_guard.upper()
-                if not os.path.isfile(config_file):
-                    if not os.path.isdir(config_dir):
-                        os.makedirs(config_dir)
-                    outfile = open(config_file, 'w')
-                    outfile.write('#ifndef ' + config_file_guard + '\n')
-                    outfile.write('#define ' + config_file_guard + '\n')
-                    config = env.Configure()
-                    for fn in module.config:
-                        output = fn(env, config)
-                        for o in output:
-                            outfile.write(o)
-                            outfile.write('\n')
-                    outfile.write('#endif /*' + config_file_guard + '*/\n')
-                    config.Finish()
-    def generate_dependencies(self):
-        inheritenv = (ARGUMENTS.get('inheritenv', 'n') in 'yY1')
-        if inheritenv:
-            env = Environment(ENV=os.environ)
-        else:
-            env = Environment()
-        self.gen_mod_config(env)
-        cc = env['CC']
-        cxx = env.subst(env['CXX'])
-        if cc == '':
-            print "Missing C compiler."
-            env.Exit (1);
-        if cxx == '':
-            print "Missing C++ compiler."
-            env.Exit (1);
-        common_flags = ARGUMENTS.get('cflags', '').split(' ')
-        cxxflags = ARGUMENTS.get('cxxflags', '').split(' ')
-        ldflags = ARGUMENTS.get('ldflags', '').split(' ')
-        if cc == 'cl' and cxx == 'cl':
-            env = Environment(tools=['mingw'])
-            cc = env['CC']
-            cxx = env.subst(env['CXX'])
-        if cc == 'gcc' and cxx == 'g++':
-            common_flags.extend(['-g3', '-Wall', '-Werror'])
-            debug_flags = []
-            opti_flags = ['-O3']
-        elif cc == 'cl' and cxx == 'cl':
-            env = Environment(ENV=os.environ)
-            debug_flags = ['-W1', '-GX', '-EHsc', '-D_DEBUG', '/MDd']
-            opti_flags = ['-O2', '-EHsc', '-DNDEBUG', '/MD']
-        cc = ARGUMENTS.get ('cc', '')
-        cxx = ARGUMENTS.get ('cxx', '')
-        if cc != '':
-            env.Replace (CC = cc)
-        if cxx != '':
-            env.Replace (CXX = cxx)
-        env.Append(CCFLAGS = common_flags, 
-                    CPPDEFINES = ['RUN_SELF_TESTS'], 
-                    TARFLAGS = '-c -z', 
-                    CPPFLAGS = cxxflags, 
-                    LINKFLAGS = ldflags)
-        if env['PLATFORM'] == 'posix':
-            env.Append(LINKFLAGS = ' -z origin')
-            env.Append(RPATH=env.Literal(os.path.join('\\$$ORIGIN', os.pardir, 'lib')))
-        verbose = ARGUMENTS.get('verbose', 'n')
-        if verbose == 'n':
-            env['PRINT_CMD_LINE_FUNC'] = print_cmd_line
-        header_builder = Builder(action = Action(MyCopyAction, strfunction=MyCopyActionPrint))
-        env.Append(BUILDERS = {'MyCopyBuilder':header_builder})
-        gcxx_builder = Builder(action = Action(MyCopyAction, strfunction=MyCopyActionPrint), 
-                                emitter = GcxxEmitter)
-        env.Append(BUILDERS = {'CopyGcxxBuilder':gcxx_builder})
-        variant = Ns3BuildVariant()
-        builders = []
-
-
-        gcov_env = env.Copy()
-        gcov_env.Append(CFLAGS = ['-fprofile-arcs', '-ftest-coverage'], 
-                         CXXFLAGS = ['-fprofile-arcs', '-ftest-coverage'], 
-                         LINKFLAGS = ['-fprofile-arcs'])
-        # code coverage analysis
-        variant.static = False
-        variant.env = gcov_env
-        variant.build_root = os.path.join(self.build_dir, 'gcov')
-        builders = self.gen_mod_dep(variant)
-        for builder in builders:
-            gcov_env.Alias('gcov', builder)
-        gcov_env.Alias('lcov-report')
-        if 'lcov-report' in COMMAND_LINE_TARGETS:
-            lcov_report_dir = os.path.join(self.build_dir, 'lcov-report')
-            create_dir_command = "rm -rf " + lcov_report_dir
-            create_dir_command += " && mkdir " + lcov_report_dir + ";"
-            gcov_env.Execute(create_dir_command)
-            info_file = os.path.join(lcov_report_dir, self.name + '.info')
-            lcov_command = "utils/lcov/lcov -c -d . -o " + info_file
-            lcov_command += " --source-dirs=" + os.getcwd()
-            lcov_command += ":" + os.path.join(os.getcwd(), 
-                                                variant.build_root, 
-                                                'include')
-            gcov_env.Execute(lcov_command)
-            genhtml_command = "utils/lcov/genhtml -o " + lcov_report_dir
-            genhtml_command += " " + info_file
-            gcov_env.Execute(genhtml_command)
-
-
-
-        opt_env = env.Copy()
-        opt_env.Append(CFLAGS=opti_flags, 
-                        CXXFLAGS=opti_flags, 
-                        CPPDEFINES=['NDEBUG'])
-        # optimized static support
-        variant.static = True
-        variant.env = opt_env
-        variant.build_root = os.path.join(self.build_dir, 'opt-static')
-        builders = self.gen_mod_dep(variant)
-        for builder in builders:
-            opt_env.Alias('opt-static', builder)
-
-
-        opt_env = env.Copy()
-        opt_env.Append(CFLAGS = opti_flags, 
-                        CXXFLAGS = opti_flags, 
-                        CPPDEFINES = ['NDEBUG'])
-        # optimized shared support
-        variant.static = False
-        variant.env = opt_env
-        variant.build_root = os.path.join(self.build_dir, 'opt-shared')
-        builders = self.gen_mod_dep(variant)
-        for builder in builders:
-            opt_env.Alias('opt-shared', builder)
-
-
-        arc_env = env.Copy()
-        arc_env.Append(CFLAGS=opti_flags, 
-                        CXXFLAGS=opti_flags, 
-                        CPPDEFINES=['NDEBUG'])
-        arc_env.Append(CFLAGS=['-frandom-seed=0', '-fprofile-generate'], 
-                        CXXFLAGS=['-frandom-seed=0', '-fprofile-generate'], 
-                        LINKFLAGS=['-frandom-seed=0', '-fprofile-generate'])
-        # arc profiling
-        variant.static = False
-        variant.env = arc_env
-        variant.build_root = os.path.join(self.build_dir, 'opt-arc')
-        builders = self.gen_mod_dep(variant)
-        for builder in builders:
-            arc_env.Alias('opt-arc', builder)
-
-
-        arcrebuild_env = env.Copy()
-        arcrebuild_env.Append(CFLAGS=opti_flags, 
-                               CXXFLAGS=opti_flags, 
-                               CPPDEFINES=['NDEBUG'])
-        arcrebuild_env.Append(CFLAGS=['-frandom-seed=0', '-fprofile-use'], 
-                               CXXFLAGS=['-frandom-seed=0', '-fprofile-use'], 
-                               LINKFLAGS=['-frandom-seed=0', '-fprofile-use'])
-        # arc rebuild
-        variant.static = False
-        variant.env = arcrebuild_env
-        variant.gcxx_deps = True
-        variant.gcxx_root = os.path.join(self.build_dir, 'opt-arc')
-        variant.build_root = os.path.join(self.build_dir, 'opt-arc-rebuild')
-        builders = self.gen_mod_dep(variant)
-        for builder in builders:
-            arcrebuild_env.Alias('opt-arc-rebuild', builder)
-        variant.gcxx_deps = False
-
-
-
-
-        dbg_env = env.Copy()
-        dbg_env.Append(CFLAGS = debug_flags, 
-                       CXXFLAGS = debug_flags,
-                       CPPDEFINES = ['NS3_DEBUG_ENABLE',
-                                     'NS3_ASSERT_ENABLE'])
-        # debug static support
-        variant.static = True
-        variant.env = dbg_env
-        variant.build_root = os.path.join(self.build_dir, 'dbg-static')
-        builders = self.gen_mod_dep(variant)
-        for builder in builders:
-            dbg_env.Alias('dbg-static', builder)
-
-        dbg_env = env.Copy()
-        dbg_env.Append(CFLAGS=debug_flags, 
-                       CXXFLAGS=debug_flags,
-                       CPPDEFINES = ['NS3_DEBUG_ENABLE',
-                                     'NS3_ASSERT_ENABLE'])
-        # debug shared support
-        variant.static = False
-        variant.env = dbg_env
-        variant.build_root = os.path.join(self.build_dir, 'dbg-shared')
-        builders = self.gen_mod_dep(variant)
-        for builder in builders:
-            dbg_env.Alias('dbg-shared', builder)
-
-        env.Alias('dbg', 'dbg-shared')
-        env.Alias('opt', 'opt-shared')
-        env.Default('dbg')
-        env.Alias('all', ['dbg-shared', 'dbg-static', 'opt-shared', 'opt-static'])
-
-
-        # dist support
-        dist_env = env.Copy()
-        if dist_env['PLATFORM'] == 'posix' or dist_env['PLATFORM'] == 'darwin':
-            dist_list = []
-            for module in self.__modules:
-                for f in module.sources:
-                    dist_list.append(os.path.join(module.dir, f))
-                for f in module.headers:
-                    dist_list.append(os.path.join(module.dir, f))
-                for f in module.inst_headers:
-                    dist_list.append(os.path.join(module.dir, f))
-                for f in module.extra_dist:
-                    dist_list.append(os.path.join(module.dir, f))
-            for f in self.extra_dist:
-                dist_list.append(f)
-            dist_list.append (self.doxygen_config)
-            dist_list.append('SConstruct')
-            dist_list.append('build.py')
-
-            targets = []
-            basename = self.distname + '-' + self.version
-            for src in dist_list:
-                tgt = os.path.join(basename, src)
-                targets.append(dist_env.MyCopyBuilder(target=tgt, source=src))
-            tar = basename + '.tar.gz'
-            zip = basename + '.zip'
-            tmp_tar = os.path.join(self.build_dir, tar)
-            tmp_zip = os.path.join(self.build_dir, zip)
-            dist_tgt = [tar, zip]
-            dist_src = [tmp_tar, tmp_zip]
-            dist_env.Tar(tmp_tar, targets)
-            dist_env.Zip(tmp_zip, targets)
-            dist_builder = dist_env.MyCopyBuilder(target=dist_tgt, source=dist_src)
-            dist_env.Alias('dist', dist_builder)
-            dist_env.Append(RM_DIR=basename)
-            dist_env.AddPostAction(dist_builder, dist_env.Action(MyRmTree, 
-                                                                 strfunction=MyRmTreePrint))
-            dist_builder = dist_env.MyCopyBuilder(target=dist_tgt, source=dist_src)
-            dist_env.Alias('fastdist', dist_tgt)
-
-            # distcheck
-            distcheck_list = []
-            for src in dist_list:
-                tgt = os.path.join(self.build_dir, basename, src)
-                distcheck_list.append(tgt)
-            untar = env.Command(distcheck_list, tar, 
-                                ['cd ' + self.build_dir + ' && tar -zxf ../' + tar])
-            scons_dir = os.path.join(self.build_dir, basename)
-            distcheck_builder = env.Command('x', distcheck_list, 
-                                            ['cd ' + scons_dir + ' && scons'])
-            env.AlwaysBuild(distcheck_builder)
-            env.Alias('distcheck', distcheck_builder)
-        if self.doxygen_config != '':
-            doxy = env.Command('doc/html/*', self.doxygen_config, 
-                               ['doxygen ' + self.doxygen_config])
-            env.AlwaysBuild(doxy)
-            env.Alias('doc', doxy)
--- a/doc/build-waf.txt	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,102 +0,0 @@
-The main ns-3 build system is SCons.  Read the file build.txt
-for SCons instructions.
-
-Waf is an alternative build system, similar to SCons.  ns-3 now is
-able to build with Waf, in parallel to SCons.
-
-(http://www.freehackers.org/~tnagy/waf.html)
-
-Note: the Waf build scripts are experimental at this stage.
-Gustavo Carneiro (gjcarneiro@gmail.com) is the maintainer.
-
-=== Building with Waf ===
-
-To build ns-3 with waf type the commands:
- 1. ./waf configure [options]
- 2. ./waf
-
-[ Note: if ./waf does not exist, see the section "Note for developers" below ]
-
-To see valid configure options, type ./waf --help.  The most important
-option is -d <debug level>.  Valid debug levels (which are listed in
-./waf --help) are: ultradebug, debug, release, and optimized.
-
-The resulting binaries are placed in build/<debuglevel>/srcpath.
-
-Other waf usages include:
-
- 1. ./waf check
-    Runs the unit tests
-
- 2. ./waf --doxygen
-    Run doxygen to generate documentation
-
- 3. ./waf --lcov-report
-    Run code coverage analysis (assuming the project was configured
-with --enable-gcov)
-
- 4. ./waf --run "program [args]"
-    Run a ns3 program, given its target name, with the given
-    arguments.  This takes care of automatically modifying the the
-    path for finding the ns3 dynamic libraries in the environment
-    before running the program.  Note: the "program [args]" string is
-    parsed using POSIX shell rules.
-
- 5. ./waf --shell
-    Starts a nested system shell with modified environment to run ns3 programs.
-
-
-=== Extending ns-3 ===
-
-To add new modules:
-  1. Create the module directory under src (or src/devices, or whatever);
-  2. Add the source files to it;
-  3. Add a 'wscript' describing it;
-  4. Add the module subdirectory name to the all_modules list in src/wscript.
-
-A module's wscript file is basically a regular Waf script.  A ns-3
-module is created as a cpp/shlib object, like this:
-
-def build(bld):
-    obj = bld.create_obj('cpp', 'shlib')
-
-    ## set module name; by convention it starts with ns3-
-    obj.name = 'ns3-mymodule'
-    obj.target = obj.name 
-
-    ## list dependencies to other modules
-    obj.uselib_local = ['ns3-core'] 
-
-    ## list source files (private or public header files excluded)
-    obj.source = [
-        'mymodule.cc',
-    ]
-
-    ## list module public header files
-    headers = bld.create_obj('ns3header')
-    headers.source = [
-        'mymodule-header.h',
-    ]
-
-
-=== Note for developers ===
-
-The ns-3 code repository does not contain the waf script.  Instead,
-developers should check it out from a subversion repository:
-
-  svn checkout http://waf.googlecode.com/svn/tags/ns3/ waf
-
-[ note: 'tags/ns3' is a tag that represents the last svn version
-tested to work correctly with ns3, although 'trunk' will likely work
- as well ]
-
-Then it can be installed system-wide with 'sudo ./waf-light install'.
-When preparing a distribution, the resulting 'waf' script, which is
-self contained (no external files needed), can be easily included in
-the tarball so that users downloading ns-3 can easily build it without
-having Waf installed (although Python >= 2.3 is still needed).
-
-The command 'waf dist' can be used to create a distribution tarball.
-It includes all files in the source directory, except some particular
-extensions that are blacklisted, such as back files (ending in ~).
-
--- a/doc/build.txt	Thu Jul 19 13:17:35 2007 +0200
+++ b/doc/build.txt	Fri Sep 28 11:59:46 2007 +0100
@@ -1,186 +1,115 @@
-If you want to build ns3, you need to install scons (see
-http://www.scons.org). scons takes care of building
-the whole source tree using your system compiler. scons
-0.91.1 and 0.91.96 have been tested and are known to 
-work on linux FC5, Mac os X and MinGW.
+The Waf build system is used to build ns-3.  Waf is a Python-based
+build system (http://www.freehackers.org/~tnagy/waf.html)
+
+=== Installing Waf ===
 
-To start a build, you can just type 'scons' which
-will generate a debug shared build by default, located
-in the directory 'build-dir/dbg-shared/bin' and
-'build-dir/dbg-shared/lib'.
+If this file is part of a development release tarball, the top-level 
+ns-3 directory should contain a current waf script.
+
+However, the ns-3 Mercurial code repository does not contain the waf 
+script.  Instead, developers should check it out from a subversion 
+repository:
 
-All builds are built with debugging symbols. Debugging
-builds enable asserts while optimized builds disable them.
-On platforms which support it, rpath is used which means that
-the executable binaries generated link explicitely against
-the right libraries. This saves you the pain of having to
-setup environment variables to point to the right libraries.
+  svn checkout http://waf.googlecode.com/svn/tags/ns3/ waf
+
+[ note: 'tags/ns3' is a tag that represents the last svn version
+tested to work correctly with ns3, although 'trunk' will likely work
+ as well ]
 
-(Note:  An alternative build system (Waf) is being
-evaluated in the development branch of ns-3-dev on our server
-only (i.e., not in the release tarballs)-- see doc/build-waf.txt)
+Then it can be installed system-wide with 'sudo waf-light install'.
+When preparing a distribution, the resulting 'waf' script, which is
+self contained (no external files needed), can be easily included in
+the tarball so that users downloading ns-3 can easily build it without
+having Waf installed (although Python >= 2.3 is still needed).
 
-1) Options
-----------
+=== Building with Waf ===
 
-- verbose: if you have installed scons 0.91.96 or higher, 
-  the default build output is terse. To get a more verbose 
-  output, you need to set the 'verbose' variable to 'y'.
-Example: scons verbose=y
-- cflags: flags for the C compiler.
-Example: scons cflags="-O3 -ffast-math"
-- cxxflags: flags for the C++ compiler.
-Example: scons cxxflags="-O3 -ffast-math"
-- ldflags: flags for the linker:
-Example: scons ldflags="-L/foo -L/bar"
-- cc: the C compiler to use:
-Example: scons cc=gcc-4.0
-- cxx: the C++ compiler to use:
-Example: scons cxx=g++-4.0
-- high-precision-as-double: set to 'y' to make sure that the
-  high-precision arithmetics performed by the Time class on
-  behalf of the user will use doubles. By default, the code
-  uses 128 integers.
-Example: scons high-precision-as-double=y
-- inheritenv: set to 'y' if you want to make your compiler
-  execute within the same environment (env vars) as your own
-  shell. This is typically used to make colorgcc work.
-Example: scons inheritenv=y
+To build ns-3 with waf type the commands:
+ 1. waf configure [options]
+ 2. waf
 
-2) Targets
-----------
-
-- doc: build the doxygen documentation.
-Example: scons doc
+To see valid configure options, type waf --help.  The most important
+option is -d <debug level>.  Valid debug levels (which are listed in
+waf --help) are: ultradebug, debug, release, and optimized.  It is
+also possible to change the flags used for compilation with (e.g.):
+CXXFLAGS="-O3" waf configure.
 
-- dbg-shared: a debug build using shared libraries.
-  The files are built in 'build-dir/dbg-shared/'.
-Example: scons dbg-shared
-
-- dbg-static: a debug build using static libraries
-  The files are built in 'build-dir/dbg-static/'.
-Example: scons dbg-static
+[ Note:  Unlike some other build tools, to change the build target,
+the option must be supplied during the configure stage rather than
+the build stage (i.e., "waf -d optimized" will not work; instead, do
+"waf -d optimized configure; waf" ]
 
-- opt-shared: an optimized build using shared libraries.
-  The files are built in 'build-dir/opt-shared/'.
-Example: scons opt-shared
+The resulting binaries are placed in build/<debuglevel>/srcpath.
 
-- opt-static: an optimized build using static libraries.
-  The files are built in 'build-dir/opt-static/'.
-Example: scons opt-static
+Other waf usages include:
 
-- dbg: an alias for dbg-shared
-Example: scons dbg
-
-- opt: an alias for opt-shared
-Example: scons opt
+ 1. waf check
+    Runs the unit tests
 
-- all: alias for dbg-shared, dbg-static, opt-shared 
-  and opt-static
-Example: scons all
+ 2. waf --doxygen
+    Run doxygen to generate documentation
 
-- gcov: code coverage analysis. Build a debugging version of
-  the code for code coverage analysis in 'build-dir/gcov'. Once
-  the code has been built, you can run various applications to
-  exercise the code paths. To generate an html report from
-  the gcov data, use the lcov-report target
-
-- lcov-report: generate html report of gcov data. The output
-  is stored in 'build-dir/lcov-report/'.
+ 3. waf --lcov-report
+    Run code coverage analysis (assuming the project was configured
+with --enable-gcov)
 
-- dist: generate a release tarball and zipfile from the 
-  source tree. The tarball and zipfile name are generated
-  according to the version number stored in the SConstruct
-  file.
-Example in SConstruct:
-ns3 = Ns3 ()
-ns3.name = 'foo'
-ns3.version = '0.0.10'
-Example command: scons dist
-Example output files:
-foo-0.0.10.tar.gz
-foo-0.0.10.zip
+ 4. waf --run "program [args]"
+    Run a ns3 program, given its target name, with the given
+    arguments.  This takes care of automatically modifying the the
+    path for finding the ns3 dynamic libraries in the environment
+    before running the program.  Note: the "program [args]" string is
+    parsed using POSIX shell rules.
 
-- distcheck: generate a release tarball and zipfile and 
-  attempt to run the 'all' target for the release tarball.
-Example: scons distcheck
+ 4.1 waf --run programname --command-template "... %s ..."
 
-3) How the build system works
------------------------------
+    Same as --run, but uses a command template with %s replaced by the
+    actual program (whose name is given by --run).  This can be use to
+    run ns-3 programs with helper tools.  For example, to run unit
+    tests with valgrind, use the command:
 
-The current build system defines what are called "ns3 modules": each module
-is a set of source files, normal header files and installable header
-files. Each module also depends on a set of other modules. We build
-modules automatically in the correct order. That is, we always start
-from the module which does not depend on any other module (core) and
-proceed with the other modules and make sure that when a module is
-built, all the modules it depends upon have already been built.
+         waf --run run-tests --command-template "valgrind %s"
+
+ 5. waf --shell
+    Starts a nested system shell with modified environment to run ns3 programs.
+
+ 6. waf distclean
+    Cleans out the entire build/ directory
 
-To build a module, we:
-1) generate the .o files
-2) link the .o files together 
-3) install the installable headers in the common directory
-top_build_dir/include/ns3.
+ 7. waf dist
+    The command 'waf dist' can be used to create a distribution tarball.
+    It includes all files in the source directory, except some particular
+    extensions that are blacklisted, such as back files (ending in ~).
 
-This means that if you want to use a header from your own module, you
-should just include it: #include "foo.h" but if you want to include a
-header from another module, you need to include it with #include
-"ns3/bar.h". This allows you to make sure that our "public" ns3 headers
-do not conflict with existing system-level headers.   For instance,
-if you were to define a header called queue.h, you would include
-ns3/queue.h rather than queue.h, when including from a separate module,
-since many systems provide a queue.h system include file.  
 
-4) How to add files to a module ?
----------------------------------
+=== Extending ns-3 ===
 
-In the main SConstruct file, you can add source code
-to the add_sources method. For example, to add a foo.cc
-file to the core module, we coud do this:
-core.add_sources ('foo.cc')
-Of course, if this file implements public API, its 
-header should be installable:
-core.add_inst_headers ('foo.h')
+To add new modules:
+  1. Create the module directory under src (or src/devices, or whatever);
+  2. Add the source files to it;
+  3. Add a 'wscript' describing it;
+  4. Add the module subdirectory name to the all_modules list in src/wscript.
 
-5) How to create a new module ?
--------------------------------
+A module's wscript file is basically a regular Waf script.  A ns-3
+module is created as a cpp/shlib object, like this:
+
+def build(bld):
+    obj = bld.create_obj('cpp', 'shlib')
 
-# create a new module. First arg is the name of
-# the new module. Second arg is the directory in
-# which all source files for this module reside.
-my_module = build.Ns3Module ('my', 'src/my_dir')
-# add it to build system
-ns3.add (my_module)
-# specify module dependencies. Here, depends
-# on the 'ipv4' and 'core' modules
-my_module.add_deps (['core', 'ipv4']) 
-# add source code to build located in 
-# src/my_dir
-my_module.add_sources ([
-	'my_a.cc',
-	'my_b.cc',
-	'my_c.cc'
-])
-my_module.add_sources ([
-	'my_d.cc'
-])
-# add headers which are not public
-my_module.add_headers ([
-	'my_a.h',
-	'my_c.h'
-])
-# add headers which are public
-my_module.add_inst_headers ([
-	'my_b.h'
-])
-my_module.add_inst_headers ([
-	'my_d.h'
-])
-# if you need to link against an external library,
-# you must add 'external' dependencies. Here, the 
-# pthread library
-my_module.add_external_dep ('pthread')
-# by default, a module is conceptually a library. If you
-# want to generate an executable from a module you need to:
-my_module.set_executable ()
+    ## set module name; by convention it starts with ns3-
+    obj.name = 'ns3-mymodule'
+    obj.target = obj.name 
+
+    ## list dependencies to other modules
+    obj.uselib_local = ['ns3-core'] 
 
+    ## list source files (private or public header files excluded)
+    obj.source = [
+        'mymodule.cc',
+    ]
+
+    ## list module public header files
+    headers = bld.create_obj('ns3header')
+    headers.source = [
+        'mymodule-header.h',
+    ]
+
--- a/doc/doxygen.conf	Thu Jul 19 13:17:35 2007 +0200
+++ b/doc/doxygen.conf	Fri Sep 28 11:59:46 2007 +0100
@@ -450,7 +450,7 @@
 # directories like "/usr/src/myproject". Separate the files or directories 
 # with spaces.
 
-INPUT                  = src doc/main.txt 
+INPUT                  = src doc/main.txt doc/trace-source-list.h doc/tracing.h
 
 # If the value of the INPUT tag contains directories, you can use the 
 # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
@@ -514,7 +514,7 @@
 # directories that contain image that are included in the documentation (see 
 # the \image command).
 
-IMAGE_PATH             = 
+IMAGE_PATH             = doc
 
 # The INPUT_FILTER tag can be used to specify a program that doxygen should 
 # invoke to filter for each input file. Doxygen will invoke the filter program 
@@ -999,7 +999,7 @@
 # undefined via #undef or recursively expanded use the := operator 
 # instead of the = operator.
 
-PREDEFINED             = RUN_SELF_TESTS NS3_DEBUG_ENABLE
+PREDEFINED             = RUN_SELF_TESTS NS3_DEBUG_ENABLE NS3_ASSERT_ENABLE
 
 # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 
 # this tag can be used to specify a list of macro names that should be expanded. 
--- a/doc/main.txt	Thu Jul 19 13:17:35 2007 +0200
+++ b/doc/main.txt	Fri Sep 28 11:59:46 2007 +0100
@@ -23,6 +23,7 @@
  *    - \ref config
  *    - a base class for objects which need to support reference counting 
  *      and QueryInterface: ns3::Object and ns3::InterfaceId
+ *    - a set of low-level trace facilities integrated in the ns3::Object system: \ref tracing
  *    - a ns3::ComponentManager which can be used to manage the creation
  *      of any object which derives from ns3::Object through an ns3::ClassId
  *    - a smart-pointer class ns3::Ptr designed to work together with ns3::Object
@@ -33,11 +34,10 @@
  *      ns3::Scheduler and ns3::SchedulerFactory
  *    - a simulator class used to create, schedule and cancel events: ns3::Simulator
  *
- * The "common" module contains:
+ * The "core" module contains:
  *    - a packet class to create and manipulate simulation packets: ns3::Packet, ns3::Header, 
  *      and ns3::Trailer. This packet class also supports per-packet ns3::Tag which are
  *      globs of data which can be attached to any packet.
- *    - a set of low-level trace facilities: \ref lowleveltracing
  *
  * The "node" module contains:
  *    - a ns3::Node base class which should be subclassed by any new type of
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/namespace-2.dia	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,1658 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/">
+  <dia:diagramdata>
+    <dia:attribute name="background">
+      <dia:color val="#ffffff"/>
+    </dia:attribute>
+    <dia:attribute name="pagebreak">
+      <dia:color val="#000099"/>
+    </dia:attribute>
+    <dia:attribute name="paper">
+      <dia:composite type="paper">
+        <dia:attribute name="name">
+          <dia:string>#A4#</dia:string>
+        </dia:attribute>
+        <dia:attribute name="tmargin">
+          <dia:real val="2.8222000598907471"/>
+        </dia:attribute>
+        <dia:attribute name="bmargin">
+          <dia:real val="2.8222000598907471"/>
+        </dia:attribute>
+        <dia:attribute name="lmargin">
+          <dia:real val="2.8222000598907471"/>
+        </dia:attribute>
+        <dia:attribute name="rmargin">
+          <dia:real val="2.8222000598907471"/>
+        </dia:attribute>
+        <dia:attribute name="is_portrait">
+          <dia:boolean val="true"/>
+        </dia:attribute>
+        <dia:attribute name="scaling">
+          <dia:real val="1.0929253101348877"/>
+        </dia:attribute>
+        <dia:attribute name="fitto">
+          <dia:boolean val="true"/>
+        </dia:attribute>
+        <dia:attribute name="fitwidth">
+          <dia:int val="2"/>
+        </dia:attribute>
+        <dia:attribute name="fitheight">
+          <dia:int val="2"/>
+        </dia:attribute>
+      </dia:composite>
+    </dia:attribute>
+    <dia:attribute name="grid">
+      <dia:composite type="grid">
+        <dia:attribute name="width_x">
+          <dia:real val="1"/>
+        </dia:attribute>
+        <dia:attribute name="width_y">
+          <dia:real val="1"/>
+        </dia:attribute>
+        <dia:attribute name="visible_x">
+          <dia:int val="1"/>
+        </dia:attribute>
+        <dia:attribute name="visible_y">
+          <dia:int val="1"/>
+        </dia:attribute>
+        <dia:composite type="color"/>
+      </dia:composite>
+    </dia:attribute>
+    <dia:attribute name="color">
+      <dia:color val="#d8e5e5"/>
+    </dia:attribute>
+    <dia:attribute name="guides">
+      <dia:composite type="guides">
+        <dia:attribute name="hguides"/>
+        <dia:attribute name="vguides"/>
+      </dia:composite>
+    </dia:attribute>
+  </dia:diagramdata>
+  <dia:layer name="Background" visible="true">
+    <dia:object type="Flowchart - Box" version="0" id="O0">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-1,-27"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-1.05,-27.05;6.05,-24.95"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="-1,-27"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="7"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="2"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:attribute name="corner_radius">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="padding">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#/devices/[0-n]#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="1.1000000000000001"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="-0.65,-25.75"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#000000"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Flowchart - Box" version="0" id="O1">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-8,-39"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-8.05,-39.05;-0.95,-36.95"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="-8,-39"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="7"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="2"/>
+      </dia:attribute>
+      <dia:attribute name="inner_color">
+        <dia:color val="#e6c7c7"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:attribute name="corner_radius">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="padding">
+        <dia:real val="0.10000000000000001"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#NodeList#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="1.1000000000000001"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="-4.5,-37.75"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#000000"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="1"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Flowchart - Box" version="0" id="O2">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-1,-29"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-1.05,-29.05;6.05,-26.95"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="-1,-29"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="7"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="2"/>
+      </dia:attribute>
+      <dia:attribute name="inner_color">
+        <dia:color val="#e6c7c7"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:attribute name="corner_radius">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="padding">
+        <dia:real val="0.10000000000000001"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#Node#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="1.1000000000000001"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="2.5,-27.75"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#000000"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="1"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Flowchart - Box" version="0" id="O3">
+      <dia:attribute name="obj_pos">
+        <dia:point val="3,-16"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="2.95,-16.05;7.05,-13.95"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="3,-16"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="4"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="2"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:attribute name="corner_radius">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="padding">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#/queue#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="1.1000000000000001"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="3.35,-14.75"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#000000"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Flowchart - Box" version="0" id="O4">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-8,-37"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-8.05,-37.05;-0.95,-34.95"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="-8,-37"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="7"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="2"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:attribute name="corner_radius">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="padding">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#/nodes/[0-n]#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="1.1000000000000001"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="-7.65,-35.75"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#000000"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Flowchart - Box" version="0" id="O5">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-8,-31"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-8.05,-31.05;-3.95,-28.95"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="-8,-31"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="4"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="2"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:attribute name="corner_radius">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="padding">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#/udp#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="1.1000000000000001"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="-7.65,-29.75"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#000000"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Flowchart - Box" version="0" id="O6">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-16,-25"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-16.05,-25.05;-13.95,-22.95"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="-16,-25"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="2"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="2"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:attribute name="corner_radius">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="padding">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#/rx#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="1.1000000000000001"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="-15.65,-23.75"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#000000"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Flowchart - Box" version="0" id="O7">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-17,-19"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-17.05,-19.05;-9.95,-16.95"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="-17,-19"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="7"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="2"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:attribute name="corner_radius">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="padding">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#/netdevice#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="1.1000000000000001"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="-16.65,-17.75"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#000000"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - BezierLine" version="0" id="O8">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-4.5,-35"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-4.55754,-35.0575;3,-28.95"/>
+      </dia:attribute>
+      <dia:attribute name="bez_points">
+        <dia:point val="-4.5,-35"/>
+        <dia:point val="-4,-32"/>
+        <dia:point val="2.5,-31"/>
+        <dia:point val="2.5,-29"/>
+      </dia:attribute>
+      <dia:attribute name="corner_types">
+        <dia:enum val="0"/>
+        <dia:enum val="0"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow">
+        <dia:enum val="22"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_length">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_width">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O4" connection="13"/>
+        <dia:connection handle="3" to="O2" connection="2"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - BezierLine" version="0" id="O9">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-4.5,-35"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-8.00142,-35.0606;-4.43937,-32.8685"/>
+      </dia:attribute>
+      <dia:attribute name="bez_points">
+        <dia:point val="-4.5,-35"/>
+        <dia:point val="-5,-33"/>
+        <dia:point val="-7,-36"/>
+        <dia:point val="-7.5,-33"/>
+      </dia:attribute>
+      <dia:attribute name="corner_types">
+        <dia:enum val="0"/>
+        <dia:enum val="0"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow">
+        <dia:enum val="22"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_length">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_width">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O4" connection="13"/>
+        <dia:connection handle="3" to="O18" connection="2"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Flowchart - Box" version="0" id="O10">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-11,-31"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-11.05,-31.05;-7.95,-28.95"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="-11,-31"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="3"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="2"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:attribute name="corner_radius">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="padding">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#/ipv4#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="1.1000000000000001"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="-10.65,-29.75"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#000000"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Flowchart - Box" version="0" id="O11">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-14,-25"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-14.05,-25.05;-6.95,-22.95"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="-14,-25"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="7"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="2"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:attribute name="corner_radius">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="padding">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#/interfaces/[0-n]#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="1.1000000000000001"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="-13.65,-23.75"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#000000"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Flowchart - Box" version="0" id="O12">
+      <dia:attribute name="obj_pos">
+        <dia:point val="7,-16"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="6.95,-16.05;11.05,-13.95"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="7,-16"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="4"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="2"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:attribute name="corner_radius">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="padding">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#/rx#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="1.1000000000000001"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="7.35,-14.75"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#000000"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Flowchart - Box" version="0" id="O13">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-8,-16"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-8.05,-16.05;-3.95,-13.95"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="-8,-16"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="4"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="2"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:attribute name="corner_radius">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="padding">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#/queue#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="1.1000000000000001"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="-7.65,-14.75"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#000000"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Flowchart - Box" version="0" id="O14">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-4,-16"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-4.05,-16.05;2.05,-13.95"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="-4,-16"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="6"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="2"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:attribute name="corner_radius">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="padding">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#/rx#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="1.1000000000000001"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="-3.65,-14.75"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#000000"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Flowchart - Box" version="0" id="O15">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-7,-9"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-7.05,-9.05;-1.95,-6.95"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="-7,-9"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="5"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="2"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:attribute name="corner_radius">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="padding">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#/enqueue#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="1.1000000000000001"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="-6.65,-7.75"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#000000"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Flowchart - Box" version="0" id="O16">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-7,-7"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-7.05,-7.05;-1.95,-4.95"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="-7,-7"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="5"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="2"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:attribute name="corner_radius">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="padding">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#/dequeue#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="1.1000000000000001"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="-6.65,-5.75"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#000000"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Flowchart - Box" version="0" id="O17">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-7,-5"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-7.05,-5.05;-1.95,-2.95"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="-7,-5"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="5"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="2"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:attribute name="corner_radius">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="padding">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#/drop#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="1.1000000000000001"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="-6.65,-3.75"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#000000"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Flowchart - Box" version="0" id="O18">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-11,-33"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-11.05,-33.05;-3.95,-30.95"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="-11,-33"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="7"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="2"/>
+      </dia:attribute>
+      <dia:attribute name="inner_color">
+        <dia:color val="#e6c7c7"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:attribute name="corner_radius">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="padding">
+        <dia:real val="0.10000000000000001"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#InternetNode#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="1.1000000000000001"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="-7.5,-31.75"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#000000"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="1"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Flowchart - Box" version="0" id="O19">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-8,-18"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-8.05,-18.05;2.05,-15.95"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="-8,-18"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="10"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="2.0000000000000018"/>
+      </dia:attribute>
+      <dia:attribute name="inner_color">
+        <dia:color val="#e6c7c7"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:attribute name="corner_radius">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="padding">
+        <dia:real val="0.10000000000000001"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#PointToPointNetDevice#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="1.1000000000000001"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="-3,-16.75"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#000000"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="1"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Flowchart - Box" version="0" id="O20">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-7,-11"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-7.05,-11.05;-1.95,-8.95"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="-7,-11"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="5"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="2"/>
+      </dia:attribute>
+      <dia:attribute name="inner_color">
+        <dia:color val="#e6c7c7"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:attribute name="corner_radius">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="padding">
+        <dia:real val="0.10000000000000001"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#Queue#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="1.1000000000000001"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="-4.5,-9.75"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#000000"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="1"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Flowchart - Box" version="0" id="O21">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-16,-27"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-16.05,-27.05;-6.95,-24.95"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="-16,-27"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="9"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="2"/>
+      </dia:attribute>
+      <dia:attribute name="inner_color">
+        <dia:color val="#e6c7c7"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:attribute name="corner_radius">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="padding">
+        <dia:real val="0.10000000000000001"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#Ipv4L3Protocol#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="1.1000000000000001"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="-11.5,-25.75"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#000000"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="1"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Flowchart - Box" version="0" id="O22">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-17,-21"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-17.05,-21.05;-9.95,-18.95"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="-17,-21"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="7"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="2"/>
+      </dia:attribute>
+      <dia:attribute name="inner_color">
+        <dia:color val="#e6c7c7"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:attribute name="corner_radius">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="padding">
+        <dia:real val="0.10000000000000001"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#Ipv4Interface#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="1.1000000000000001"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="-13.5,-19.75"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#000000"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="1"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Flowchart - Box" version="0" id="O23">
+      <dia:attribute name="obj_pos">
+        <dia:point val="3,-18"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="2.95,-18.05;11.05,-15.95"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="3,-18"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="8.0000000000000071"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="2"/>
+      </dia:attribute>
+      <dia:attribute name="inner_color">
+        <dia:color val="#e6c7c7"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:attribute name="corner_radius">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="padding">
+        <dia:real val="0.10000000000000001"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#CsmaNetDevice#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="1.1000000000000001"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="7,-16.75"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#000000"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="1"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - BezierLine" version="0" id="O24">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-9.5,-29"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-12,-29.0606;-9.38388,-26.95"/>
+      </dia:attribute>
+      <dia:attribute name="bez_points">
+        <dia:point val="-9.5,-29"/>
+        <dia:point val="-9,-27"/>
+        <dia:point val="-11.5,-29"/>
+        <dia:point val="-11.5,-27"/>
+      </dia:attribute>
+      <dia:attribute name="corner_types">
+        <dia:enum val="0"/>
+        <dia:enum val="0"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow">
+        <dia:enum val="22"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_length">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_width">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O10" connection="13"/>
+        <dia:connection handle="3" to="O21" connection="2"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - BezierLine" version="0" id="O25">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-10.5,-23"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-13.9972,-23.0606;-10.4066,-20.8302"/>
+      </dia:attribute>
+      <dia:attribute name="bez_points">
+        <dia:point val="-10.5,-23"/>
+        <dia:point val="-10,-21"/>
+        <dia:point val="-14,-23"/>
+        <dia:point val="-13.5,-21"/>
+      </dia:attribute>
+      <dia:attribute name="corner_types">
+        <dia:enum val="0"/>
+        <dia:enum val="0"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow">
+        <dia:enum val="22"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_length">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_width">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O11" connection="13"/>
+        <dia:connection handle="3" to="O22" connection="2"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - BezierLine" version="0" id="O26">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-6,-14"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-6.05,-14.05;-4.0028,-10.8302"/>
+      </dia:attribute>
+      <dia:attribute name="bez_points">
+        <dia:point val="-6,-14"/>
+        <dia:point val="-6,-11"/>
+        <dia:point val="-5,-13"/>
+        <dia:point val="-4.5,-11"/>
+      </dia:attribute>
+      <dia:attribute name="corner_types">
+        <dia:enum val="0"/>
+        <dia:enum val="0"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow">
+        <dia:enum val="22"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_length">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_width">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O13" connection="13"/>
+        <dia:connection handle="3" to="O20" connection="2"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - BezierLine" version="0" id="O27">
+      <dia:attribute name="obj_pos">
+        <dia:point val="5,-14"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="4.95,-14.05;7,-10.95"/>
+      </dia:attribute>
+      <dia:attribute name="bez_points">
+        <dia:point val="5,-14"/>
+        <dia:point val="5,-12"/>
+        <dia:point val="6.5,-13"/>
+        <dia:point val="6.5,-11"/>
+      </dia:attribute>
+      <dia:attribute name="corner_types">
+        <dia:enum val="0"/>
+        <dia:enum val="0"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow">
+        <dia:enum val="22"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_length">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_width">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O3" connection="13"/>
+        <dia:connection handle="3" to="O33" connection="2"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - BezierLine" version="0" id="O28">
+      <dia:attribute name="obj_pos">
+        <dia:point val="2.5,-25"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-3.5,-25.05;2.55,-17.95"/>
+      </dia:attribute>
+      <dia:attribute name="bez_points">
+        <dia:point val="2.5,-25"/>
+        <dia:point val="2.5,-23"/>
+        <dia:point val="-3,-20"/>
+        <dia:point val="-3,-18"/>
+      </dia:attribute>
+      <dia:attribute name="corner_types">
+        <dia:enum val="0"/>
+        <dia:enum val="0"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow">
+        <dia:enum val="22"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_length">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_width">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O0" connection="13"/>
+        <dia:connection handle="3" to="O19" connection="2"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - BezierLine" version="0" id="O29">
+      <dia:attribute name="obj_pos">
+        <dia:point val="2.5,-25"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="2.45,-25.05;7.5,-17.95"/>
+      </dia:attribute>
+      <dia:attribute name="bez_points">
+        <dia:point val="2.5,-25"/>
+        <dia:point val="2.5,-23"/>
+        <dia:point val="7,-20"/>
+        <dia:point val="7,-18"/>
+      </dia:attribute>
+      <dia:attribute name="corner_types">
+        <dia:enum val="0"/>
+        <dia:enum val="0"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow">
+        <dia:enum val="22"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_length">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_width">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O0" connection="13"/>
+        <dia:connection handle="3" to="O23" connection="2"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Flowchart - Box" version="0" id="O30">
+      <dia:attribute name="obj_pos">
+        <dia:point val="4,-9"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="3.95,-9.05;9.05,-6.95"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="4,-9"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="5"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="2"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:attribute name="corner_radius">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="padding">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#/enqueue#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="1.1000000000000001"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="4.35,-7.75"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#000000"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Flowchart - Box" version="0" id="O31">
+      <dia:attribute name="obj_pos">
+        <dia:point val="4,-7"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="3.95,-7.05;9.05,-4.95"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="4,-7"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="5"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="2"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:attribute name="corner_radius">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="padding">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#/dequeue#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="1.1000000000000001"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="4.35,-5.75"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#000000"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Flowchart - Box" version="0" id="O32">
+      <dia:attribute name="obj_pos">
+        <dia:point val="4,-5"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="3.95,-5.05;9.05,-2.95"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="4,-5"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="5"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="2"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:attribute name="corner_radius">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="padding">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#/drop#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="1.1000000000000001"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="4.35,-3.75"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#000000"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="0"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Flowchart - Box" version="0" id="O33">
+      <dia:attribute name="obj_pos">
+        <dia:point val="4,-11"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="3.95,-11.05;9.05,-8.95"/>
+      </dia:attribute>
+      <dia:attribute name="elem_corner">
+        <dia:point val="4,-11"/>
+      </dia:attribute>
+      <dia:attribute name="elem_width">
+        <dia:real val="5"/>
+      </dia:attribute>
+      <dia:attribute name="elem_height">
+        <dia:real val="2"/>
+      </dia:attribute>
+      <dia:attribute name="inner_color">
+        <dia:color val="#e6c7c7"/>
+      </dia:attribute>
+      <dia:attribute name="show_background">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:attribute name="corner_radius">
+        <dia:real val="0.40000000000000002"/>
+      </dia:attribute>
+      <dia:attribute name="padding">
+        <dia:real val="0.10000000000000001"/>
+      </dia:attribute>
+      <dia:attribute name="text">
+        <dia:composite type="text">
+          <dia:attribute name="string">
+            <dia:string>#Queue#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="font">
+            <dia:font family="sans" style="0" name="Helvetica"/>
+          </dia:attribute>
+          <dia:attribute name="height">
+            <dia:real val="1.1000000000000001"/>
+          </dia:attribute>
+          <dia:attribute name="pos">
+            <dia:point val="6.5,-9.75"/>
+          </dia:attribute>
+          <dia:attribute name="color">
+            <dia:color val="#000000"/>
+          </dia:attribute>
+          <dia:attribute name="alignment">
+            <dia:enum val="1"/>
+          </dia:attribute>
+        </dia:composite>
+      </dia:attribute>
+    </dia:object>
+    <dia:object type="Standard - BezierLine" version="0" id="O34">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-10,-18"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-10.0693,-20.6883;-5.0028,-17.8302"/>
+      </dia:attribute>
+      <dia:attribute name="bez_points">
+        <dia:point val="-10,-18"/>
+        <dia:point val="-8,-21"/>
+        <dia:point val="-6.5,-22"/>
+        <dia:point val="-5.5,-18"/>
+      </dia:attribute>
+      <dia:attribute name="corner_types">
+        <dia:enum val="0"/>
+        <dia:enum val="0"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow">
+        <dia:enum val="22"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_length">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_width">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O7" connection="8"/>
+        <dia:connection handle="3" to="O19" connection="1"/>
+      </dia:connections>
+    </dia:object>
+    <dia:object type="Standard - BezierLine" version="0" id="O35">
+      <dia:attribute name="obj_pos">
+        <dia:point val="-10,-18"/>
+      </dia:attribute>
+      <dia:attribute name="obj_bb">
+        <dia:rectangle val="-10.0702,-22.2491;5.4972,-17.8302"/>
+      </dia:attribute>
+      <dia:attribute name="bez_points">
+        <dia:point val="-10,-18"/>
+        <dia:point val="-1,-25"/>
+        <dia:point val="4,-22"/>
+        <dia:point val="5,-18"/>
+      </dia:attribute>
+      <dia:attribute name="corner_types">
+        <dia:enum val="0"/>
+        <dia:enum val="0"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow">
+        <dia:enum val="22"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_length">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:attribute name="end_arrow_width">
+        <dia:real val="0.5"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O7" connection="8"/>
+        <dia:connection handle="3" to="O23" connection="1"/>
+      </dia:connections>
+    </dia:object>
+  </dia:layer>
+</dia:diagram>
Binary file doc/namespace-2.png has changed
--- a/doc/release_steps.txt	Thu Jul 19 13:17:35 2007 +0200
+++ b/doc/release_steps.txt	Fri Sep 28 11:59:46 2007 +0100
@@ -5,11 +5,16 @@
    - revise and check in RELEASE_NOTES
    - update and check in VERSION to the latest release number
 2. make a new "architecture.pdf" document and place it in the doc/ directory
-3. scons dist
-4. test tarball on release platforms (run-tests and simple-p2p)
+3. cd ns-3-dev; ./waf configure; ./waf dist
+4. test tarball on release platforms (waf check and maybe some other scripts)
 5. tag ns-3-dev with "release ns-3.0.X"
-6. clone the ns-3-dev and place it on the repository
-7. upload "ns-3.0.x.tar.gz" to the releases/ directory on the server
+  - hg tag "release ns-3.0.x"
+  - hg push 
+6. clone the tagged ns-3-dev and place it on the repository
+  - ssh code.nsnam.org; sudo; su code;
+  - cp -r /home/code/repos/ns-3-dev /home/code/repos/ns-3.0.x
+  - cd /home/code/repos/ns-3.0.x/.hg and edit the hgrc appropriately
+7. upload "ns-3.0.x.tar.bz2" to the releases/ directory on the server
 8. update web page
    - add link to news.html
    - update download.html
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/trace-source-list.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,204 @@
+///
+/// \ingroup TraceSourceList
+/// \brief send ipv4 packet to outgoing interface
+/// \param arg1 the trace context associated to the connected trace source.
+/// \param arg2 packet sent.
+/// \param arg3 index of output ipv4 interface.
+///
+///
+/// The path to this trace source is: /nodes/[0-n]/ipv4/tx.
+///
+/// The following classes can be extracted from \p arg1 with 
+/// ns3::TraceContext::GetElement:
+///  - ns3::NodeListIndex
+///  - ns3::Ipv4L3ProtocolTraceContextElement
+void TraceSinkCallback0 (const TraceContext & arg1, const Packet & arg2, uint32_t arg3);
+
+///
+/// \ingroup TraceSourceList
+/// \brief receive ipv4 packet from incoming interface
+/// \param arg1 the trace context associated to the connected trace source.
+/// \param arg2 packet received.
+/// \param arg3 index of input ipv4 interface.
+///
+///
+/// The path to this trace source is: /nodes/[0-n]/ipv4/rx.
+///
+/// The following classes can be extracted from \p arg1 with 
+/// ns3::TraceContext::GetElement:
+///  - ns3::NodeListIndex
+///  - ns3::Ipv4L3ProtocolTraceContextElement
+void TraceSinkCallback1 (const TraceContext & arg1, const Packet & arg2, uint32_t arg3);
+
+///
+/// \ingroup TraceSourceList
+/// \brief drop ipv4 packet
+/// \param arg1 the trace context associated to the connected trace source.
+/// \param arg2 packet dropped.
+///
+///
+/// The path to this trace source is: /nodes/[0-n]/ipv4/drop.
+///
+/// The following classes can be extracted from \p arg1 with 
+/// ns3::TraceContext::GetElement:
+///  - ns3::NodeListIndex
+///  - ns3::Ipv4L3ProtocolTraceContextElement
+void TraceSinkCallback2 (const TraceContext & arg1, const Packet & arg2);
+
+///
+/// \ingroup TraceSourceList
+/// \brief store packet in queue
+/// \param arg1 the trace context associated to the connected trace source.
+/// \param arg2 packet queued.
+///
+///
+/// The path to this trace source is: /nodes/[0-n]/devices/[0-n]/queue/enqueue.
+///
+/// The following classes can be extracted from \p arg1 with 
+/// ns3::TraceContext::GetElement:
+///  - ns3::NodeListIndex
+///  - ns3::NodeNetDeviceIndex
+///  - ns3::QueueTraceType
+void TraceSinkCallback3 (const TraceContext & arg1, const Packet & arg2);
+
+///
+/// \ingroup TraceSourceList
+/// \brief remove packet from queue
+/// \param arg1 the trace context associated to the connected trace source.
+/// \param arg2 packet dequeued.
+///
+///
+/// The path to this trace source is: /nodes/[0-n]/devices/[0-n]/queue/dequeue.
+///
+/// The following classes can be extracted from \p arg1 with 
+/// ns3::TraceContext::GetElement:
+///  - ns3::NodeListIndex
+///  - ns3::NodeNetDeviceIndex
+///  - ns3::QueueTraceType
+void TraceSinkCallback4 (const TraceContext & arg1, const Packet & arg2);
+
+///
+/// \ingroup TraceSourceList
+/// \brief drop packet from queue
+/// \param arg1 the trace context associated to the connected trace source.
+/// \param arg2 packet dropped.
+///
+///
+/// The path to this trace source is: /nodes/[0-n]/devices/[0-n]/queue/drop.
+///
+/// The following classes can be extracted from \p arg1 with 
+/// ns3::TraceContext::GetElement:
+///  - ns3::NodeListIndex
+///  - ns3::NodeNetDeviceIndex
+///  - ns3::QueueTraceType
+void TraceSinkCallback5 (const TraceContext & arg1, const Packet & arg2);
+
+///
+/// \ingroup TraceSourceList
+/// \brief receive MAC packet
+/// \param arg1 the trace context associated to the connected trace source.
+/// \param arg2 packet received.
+///
+///
+/// The path to this trace source is: /nodes/[0-n]/devices/[0-n]/rx.
+///
+/// The following classes can be extracted from \p arg1 with 
+/// ns3::TraceContext::GetElement:
+///  - ns3::NodeListIndex
+///  - ns3::NodeNetDeviceIndex
+///  - ns3::PointToPointTraceType
+void TraceSinkCallback6 (const TraceContext & arg1, const Packet & arg2);
+
+///
+/// \ingroup TraceSourceList
+/// \brief receive MAC packet
+/// \param arg1 the trace context associated to the connected trace source.
+/// \param arg2 packet received.
+///
+///
+/// The path to this trace source is: /nodes/[0-n]/devices/[0-n]/rx.
+///
+/// The following classes can be extracted from \p arg1 with 
+/// ns3::TraceContext::GetElement:
+///  - ns3::NodeListIndex
+///  - ns3::NodeNetDeviceIndex
+///  - ns3::CsmaTraceType
+void TraceSinkCallback7 (const TraceContext & arg1, const Packet & arg2);
+
+///
+/// \ingroup TraceSourceList
+/// \brief drop MAC packet
+/// \param arg1 the trace context associated to the connected trace source.
+/// \param arg2 packet dropped.
+///
+///
+/// The path to this trace source is: /nodes/[0-n]/devices/[0-n]/drop.
+///
+/// The following classes can be extracted from \p arg1 with 
+/// ns3::TraceContext::GetElement:
+///  - ns3::NodeListIndex
+///  - ns3::NodeNetDeviceIndex
+///  - ns3::CsmaTraceType
+void TraceSinkCallback8 (const TraceContext & arg1, const Packet & arg2);
+
+///
+/// \ingroup TraceSourceList
+/// \brief The value of the speed vector changed
+/// \param arg1 the trace context associated to the connected trace source.
+/// \param arg2 the mobility model whose course changed.
+///
+///
+/// The path to this trace source is: /nodes/[0-n]/$MobilityModelNotifier/course-change.
+///
+/// The following classes can be extracted from \p arg1 with 
+/// ns3::TraceContext::GetElement:
+///  - ns3::NodeListIndex
+void TraceSinkCallback9 (const TraceContext & arg1, Ptr<const MobilityModel> arg2);
+
+///
+/// \ingroup TraceSourceList
+/// \brief send ipv4 packet to outgoing interface
+/// \param arg1 the trace context associated to the connected trace source.
+/// \param arg2 packet sent.
+/// \param arg3 index of output ipv4 interface.
+///
+///
+/// The path to this trace source is: /nodes/[0-n]/$Ipv4L3Protocol/tx.
+///
+/// The following classes can be extracted from \p arg1 with 
+/// ns3::TraceContext::GetElement:
+///  - ns3::NodeListIndex
+///  - ns3::Ipv4L3ProtocolTraceContextElement
+void TraceSinkCallback10 (const TraceContext & arg1, const Packet & arg2, uint32_t arg3);
+
+///
+/// \ingroup TraceSourceList
+/// \brief receive ipv4 packet from incoming interface
+/// \param arg1 the trace context associated to the connected trace source.
+/// \param arg2 packet received.
+/// \param arg3 index of input ipv4 interface.
+///
+///
+/// The path to this trace source is: /nodes/[0-n]/$Ipv4L3Protocol/rx.
+///
+/// The following classes can be extracted from \p arg1 with 
+/// ns3::TraceContext::GetElement:
+///  - ns3::NodeListIndex
+///  - ns3::Ipv4L3ProtocolTraceContextElement
+void TraceSinkCallback11 (const TraceContext & arg1, const Packet & arg2, uint32_t arg3);
+
+///
+/// \ingroup TraceSourceList
+/// \brief drop ipv4 packet
+/// \param arg1 the trace context associated to the connected trace source.
+/// \param arg2 packet dropped.
+///
+///
+/// The path to this trace source is: /nodes/[0-n]/$Ipv4L3Protocol/drop.
+///
+/// The following classes can be extracted from \p arg1 with 
+/// ns3::TraceContext::GetElement:
+///  - ns3::NodeListIndex
+///  - ns3::Ipv4L3ProtocolTraceContextElement
+void TraceSinkCallback12 (const TraceContext & arg1, const Packet & arg2);
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/tracing.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,576 @@
+/**
+ * \defgroup TraceSourceList List of trace sources
+ */
+
+/**
+ * \defgroup tracing Tracing
+ *
+ * The flexibility of the ns-3 tracing system comes at the cost of quite
+ * a bit of complexity so, before trying to use the low-level aspects
+ * of the tracing API, it is important to focus on some basic definitions:
+ *
+ * - A trace source is an object instance which can report trace events
+ *   to a set of listening trace sinks.
+ *
+ * - A trace sink is a user-provided callback (a function) which can
+ *   be connected to a set of trace sources to receive the events generated
+ *   by each trace source.
+ *
+ * - A trace resolver is an object which allows users to establish 
+ *   connections between a set of trace sources and a set of trace sinks.
+ *
+ * \section TraceSource Generating Trace Events
+ *
+ * So, what does it look like in practice ? First, let's look at trace
+ * sources. We have two types of trace sources: numeric, and, normal 
+ * trace sources. Numeric trace sources behave as normal c++ integers 
+ * or c++ floating point numbers except that they report as trace events 
+ * each change of their value. For example:
+ * \code
+ * class MyModel 
+ * {
+ * public:
+ *   void DoSomething (void) 
+ *   {
+ *     // use the "int" trace source just 
+ *     // like any other "int" variable.
+ *     m_cwnd *= 2;
+ *     m_cwnd += 4;
+ *     if (m_cwnd > 100)
+ *       {
+ *         // do something.
+ *       }
+ *   }
+ * private:
+ *   // declare an instance of a "int" trace source
+ *   SVTraceSource<int> m_cwnd;
+ * };
+ * \endcode
+ * Normal trace sources, on the other hand, allow you to trace the
+ * call of arbitrary functions and methods, as shown below. They are
+ * typically used to track "rx", "tx", or "drop" events but could
+ * also be used to track route change events, or position change
+ * events:
+ * \code
+ * class MyModel 
+ * {
+ * public:
+ *   void DoSomething (Packet packet) 
+ *   {
+ *     // report this event on packet
+ *     m_doSomething (packet);
+ *     // do something
+ *   }
+ * private:
+ *   // report every "something" function call.
+ *   CallbackTraceSource<Packet> m_doSomething;
+ * };
+ * \endcode
+ * Every type of trace source derives from the ns3::TraceSource base class.
+ * As of today, the set of concrete subclasses is relatively short:
+ * ns3::CallbackTraceSource, ns3::SvTraceSource, ns3::UvTraceSource, and,
+ * ns3::FvTraceSource.
+ *
+ * \section TraceSink Receiving Trace Events
+ *
+ * To receive these trace events, a user should specify a set of trace sinks.
+ * For example, to receive the "int" and the "something" events shown in the
+ * examples above, a user would declare the following functions:
+ * \code
+ * // oldValue and newValue contain the previous and new values of 
+ * // the connected SVTraceSource<int> trace source.
+ * void 
+ * CwndTraceSink (const TraceContext &context, int64_t oldValue, int64_t newValue)
+ * {
+ *   // for example, print the new value:
+ *   std::cout << "cwnd=" << newValue << std::endl;
+ * }
+ * void 
+ * DoSomethingTraceSink (const TraceContext &context, Packet packet)
+ * {
+ *   // for example, print the arguments
+ *   std::cout << "packet " << packet << std::endl;
+ * }
+ * \endcode
+ * Each of these sink function takes, as a first argument, a reference to a 
+ * const TraceContext object. This context object contains information which
+ * describes the instance of the connected trace source: that information is
+ * setup during the connection process and does not change afterwards
+ * The type and the number of the other arguments to each trace sink depends
+ * on the type of the connected trace source: it conveys per-event information
+ * from the trace source to the trace sink. For example, UVTraceSource and 
+ * SVTraceSource trace sources require two extra arguments. The former requires
+ * two unsigned 64 bit integers while the latter requires two signed 64 bit 
+ * integers. More generally, users can consult the \ref TraceSourceList
+ * to figure out the arguments which a trace sink is required to receive
+ * for each trace source: a signature of the user trace sink must match 
+ * _exactly_ the signature documented in the \ref TraceSourceList.
+ *
+ *
+ * \section TraceSourceSimpleExport A simple way to connect Trace Sources with Trace Sinks
+ *
+ * The crux of the complexity of the ns-3 tracing system comes from its 
+ * flexible system used to connect trace sources to trace sinks but what is really
+ * nice about it is that it is not necessary to use it to setup simple traces.
+ * 
+ * The simplest way to export a set of trace sources to a user, for example, 
+ * during the early prototyping phases of a system, is to add a set of public methods
+ * to give to your users access to the trace source object instances you use to generate
+ * trace events:
+ * \code
+ * class MyModel 
+ * {
+ * public:
+ *   void DoSomething (Packet packet) 
+ *   {
+ *     // report this event on packet
+ *     m_doSomething (packet);
+ *     // do something
+ *   }
+ *   CallbackTraceSource<Packet> *PeekSomethingTraceSource (void) const 
+ *   {
+ *     return &m_doSomething
+ *   }
+ * private:
+ *   // report every "something" function call.
+ *   CallbackTraceSource<Packet> m_doSomething;
+ * };
+ * \endcode
+ * If your users hold a pointer to an instance of MyModel, and if they want to connect
+ * a MySomethingSink, they can simply do the following which invokes the 
+ * TraceSource::AddCallback method and creates a Callback object from the user's
+ * sink with the MakeCallback function.
+ * \code
+ * void 
+ * MySomethingSink (const TraceContext &context, Packet packet)
+ * {
+ *   // do whatever you want.
+ * }
+ * MyModel *model = ...;
+ * CallbackTraceSource<Packet> *source = model->PeekSomethingTraceSource ();
+ * source->AddCallback (MakeCallback (&MySomethingSink));
+ * \endcode
+ *
+ * The full power of the tracing system comes however from its ns3::NodeList::Connect
+ * method which is described in the following sections.
+ *
+ * \section TraceConnection Connecting Trace Sources to Trace Sinks
+ * 
+ * If a trace source is integrated in the ns-3 trace connection facility, a user 
+ * should call the ns3::NodeList::Connect method to establish a connection between
+ * a trace sink and a set of matching trace sources. The second argument to that
+ * method is a callback to the user's trace sink.
+ * That callback is easy to construct: call ns3::MakeCallback and you are done. The
+ * first argument is a string whose format is similar to a unix path and which is 
+ * used to uniquely identify the set of trace sources you want to connect to.
+ * The set of acceptable path strings is also documented in the \ref TraceSourceList.
+ *
+ * So, what does this look like from the perspective of a user ? If we wanted to 
+ * connect to a trace source defined somewhere deep into the a set of NetDevice objects
+ * located in some nodes of the system, we could write the following:
+ * \code
+ * void 
+ * DoSomethingTraceSink (const TraceContext &context, Packet packet)
+ * {
+ *   // for example, print the arguments
+ *   std::cout << "packet: " << packet << std::endl;
+ * }
+ * // connect the above sink to a matching trace source
+ * NodeList::Connect ("/nodes/* /devices/* /rx", MakeCallback &DoSomethingTraceSink);
+ * \endcode
+ *
+ * The connection path string "/nodes/* /devices/* /rx" matches the "rx" trace source
+ * located in every netdevice located in every node. The syntax of that path string
+ * is loosely based on regular expressions so, a user could conceivably connect
+ * to the trace sources present in only one node identified by node index:
+ * "/nodex/3/devices/* /rx".
+ *
+ * The matching algorithm used here is very useful since it allows you to connect
+ * at once a large set of trace sources to a single sink but it introduces another 
+ * problem: it becomes impossible when you receive an event in your trace sink to
+ * know from _which_ trace source the event is coming from. In our example, the
+ * trace source might be coming from the NetDevice number 2 of Node 10 or Netdevice
+ * number 0 of Node 5. In both cases, you might need to know which of these NetDevice
+ * is generating this event, if only to generate some ascii trace dump. Another 
+ * similar use-case is that you might have connected the same trace sink to
+ * multiple types of events which have the same signature: it is quite common
+ * to receive all tx, rx, and drop events in the same trace sink and that would be
+ * quite trivial to achieve with a string such as: "/nodes/* /devices/* /*"
+ *
+ * The source of a trace event can be retrieved from a trace sink using 
+ * different means: the simplest
+ * way to get this information is to use the builtin printing facility of
+ * the TraceContext object:
+ * \code
+ * void 
+ * DoSomethingTraceSink (const TraceContext &context, Packet packet)
+ * {
+ *   // for example, print the arguments
+ *   std::cout << "context=\"" << context << "\" packet: " << packet << std::endl;
+ * }
+ * \endcode
+ * The above code is going to generate output which looks like the following:
+ * \code
+ * context="nodeid=2 device=0 dev-rx" packet: IPV4(tos 0x0 ttl 64 id 0 offset ...
+ * context="nodeid=1 device=0 dev-rx" packet: IPV4(tos 0x0 ttl 64 id 0 offset ...
+ * ...
+ * \endcode
+ *
+ * Another more advanced way to get information out of a TraceContext is to call its
+ * ns3::TraceContext::GetElement method. This method takes as its first and only
+ * argument an instance of the object we want to read and the list of available
+ * object instances we can read from a TraceContext is documented, once again,
+ * in the \ref TraceSourceList. For example, we could write the following to
+ * generate adhoc trace output:
+ * \code
+ * void DeviceRxSink (const TraceContext &context, const Packet &packet)
+ * {
+ *   NodeListIndex nodeIndex;
+ *   NodeNetDeviceIndex deviceIndex;
+ *   context.GetElement (nodeIndex);
+ *   context.GetElement (deviceIndex);
+ *   std::cout << "node-index=" << nodeIndex.Get ();
+ *   std::cout << ", device-index=" << deviceIndex.Get ();
+ *   std::cout << ", packet: " << packet;
+ *   std::cout << std::endl;
+ * }
+ * \endcode
+ *
+ * \section ExportingTraceSources Exporting new Trace Sources
+ *
+ * Using existing trace sources to connect them to a set of adhoc trace sinks
+ * is not really complicated but, setting up new trace sources which can hook
+ * in this automatic connection system is a bit more complicated.
+ *
+ * So far, we know that a model author can generate trace events really easily:
+ * \code
+ * class MyModel 
+ * {
+ * public:
+ *   void DoSomething (Packet packet) 
+ *   {
+ *     // report this event on packet with value
+ *     m_doSomething (packet);
+ *     // do something
+ *   }
+ * private:
+ *   // report every "something" function call.
+ *   CallbackTraceSource<Packet> m_doSomething;
+ * };
+ * \endcode
+ *
+ * To make these new trace sources available to the rest of the connection system,
+ * the first step is to make sure that your model object derives from the ns3::Object
+ * base class either directly (as shown below) or indirectly through another base class:
+ * \code
+ * class MyModel : public Object {...};
+ * // or:
+ * class SomeOtherObject : public Object {...};
+ * class MyModel : public SomeOtherObject {...};
+ * \endcode
+ *
+ * This is pretty trivial and lays the ground for the second step: overriding the
+ * ns3::Object::GetTraceResolver method:
+ * \code
+ * class MyModel : public MyParent
+ * {
+ * public:
+ *   // declare overriden method
+ *   virtual Ptr<TraceResolver> GetTraceResolver (void) const;
+ * private:
+ *   // the new trace source to export.
+ *   CallbackTraceSource<Packet> m_rxSource;
+ * };
+ * \endcode
+ *
+ * To implement this method, you could attempt to implement a new subclass of
+ * the ns3::TraceResolver base class and return an instance from this method but
+ * this would be very hard. Instead, you should use the helper class
+ * ns3::CompositeTraceResolver to register your trace sources and chain up to
+ * your parent:
+ * \code
+ * Ptr<TraceResolver>
+ * MyModel::GetTraceResolver (void) const
+ * {
+ *   // create an empty trace resolver
+ *   Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
+ *   // register m_rxSource
+ *   resolver->AddSource ("rx", // the name of the trace source in the path string
+ *                        TraceDoc ("some help text to explain the purpose of this trace source",
+ *                                  "Packet", // the type of the first argument to the trace source
+ *                                  "the purpose of the first argument",
+ *                                  "type-of-second-argument", "purpose-of-second-argument"),
+ *                        m_rxSource // the trace source itself is registered
+ *                       );
+ *   // make sure we include the trace sources implemented in the parent.
+ *   resolver->SetParentResolver (MyParent::GetTraceResolver ());
+ *   return resolver;
+ * }
+ * \endcode
+ *
+ * Once you have written that code, you must make sure that this new method GetTraceResolver
+ * is going to be called at some point by the tracing system. If your model is located somewhere
+ * deep in MAC or PHY layer, that is, it is part of a NetDevice implementation, all you
+ * have to do is to make sure that your model is registered as a "composite" of your NetDevice
+ * subclass:
+ * \code
+ * class MyNetDevice : public NetDevice
+ * {
+ * public:
+ *   Ptr<TraceResolver> GetTraceResolver (void) const;
+ * private:
+ *   Ptr<MyModel> m_model;
+ * };
+ * 
+ * Ptr<TraceResolver>
+ * MyNetDevice::GetTraceResolver (void) const
+ * {
+ *   Ptr<CompositeTraceResolver> resolver = ...;
+ *   // register other trace source
+ *   ...
+ *   // register now your model as a "composite"
+ *   resolver->AddComposite ("my-model", m_model);
+ *   // chain up to parent.
+ *   resolver->SetParentResolver (NetDevice::GetTraceResolver ());
+ *   return resolver;
+ * }
+ * \endcode
+ * 
+ * The code above will make your "rx" trace source appear under the
+ * /nodes/xx/devices/xx/my-model/rx namespace path.
+ *
+ * If you have implemented a new layer 3 or 4 protocol object, the process to
+ * export your trace sources is quite similar. You need to subclass from
+ * ns3::Object, override the ns3::Object::GetTraceResolver method, make
+ * sure you chain up to your parent's GetTraceResolver method, and, finally,
+ * make sure that someone calls your new GetTraceResolver method. How to accomplish
+ * the latter should be documented in the node's API documentation which describes
+ * how to implement a new layer 3 or 4 protocol object.
+ *
+ * \section AdvancedTraceContext Creating new Trace Context Elements
+ *
+ * The last important feature which model developers need to understand
+ * is how to provide extra context information to trace sinks. For example,
+ * if your model exports both rx and tx trace sources which share the same 
+ * signature, it is quite natural for a user to connect to a single trace sink
+ * to both of them with a trace path string such as "/nodes/* /devices/* /(rx|tx)".
+ * In this case, it becomes necessary to be able, from the trace sink function,
+ * to tell which event triggered the call to the trace sink: a rx or a tx event.
+ *
+ * That example is detailed below with a TX, a RX, and a DROP source:
+ * \code
+ * class MyModel
+ * {
+ * private:
+ *   CallbackTraceSource<Packet> m_rxSource;
+ *   CallbackTraceSource<Packet> m_txSource;
+ *   CallbackTraceSource<Packet> m_dropSource;
+ * };
+ * \endcode
+ * When a single sink is connected to all 3 sources here, one might want
+ * to write code like the following:
+ * \code
+ * void DeviceRxSink (const TraceContext &context, const Packet &packet)
+ * {
+ *   switch (type) {
+ *     case RX:
+ *       std::cout << "rx" << std::endl;
+ *       break;
+ *     case TX:
+ *       std::cout << "tx" << std::endl;
+ *       break;
+ *     case DROP:
+ *       std::cout << "drop" << std::endl;
+ *       break;
+ *   }
+ * \endcode
+ *
+ * \subsection AdvancedTraceContextSimpleSolution The simple solution
+ *
+ * The simplest way to do achieve the result shown above is to include
+ * in the trace source an extra explicit argument which describes the source event:
+ *   - define a small enum with 3 values
+ *   - change the signature of m_rxSource, m_txSource, and m_dropSource to include
+ *     the enum
+ *   - pass the enum value in each event
+ *
+ * The resulting code is shown below:
+ * \code
+ * class MyModel
+ * {
+ * public:
+ *   // define the trace type enum.
+ *   enum TraceType {
+ *     RX,
+ *     TX,
+ *     DROP
+ *   };
+ * private:
+ *   // generate events
+ *   void NotifyRxPacket (Packet p) {
+ *     m_rxSource (p, MyModel::RX);
+ *   }
+ *   void NotifyTxPacket (Packet p) {
+ *     m_rxSource (p, MyModel::TX);
+ *   }
+ *   void NotifyDropPacket (Packet p) {
+ *     m_rxSource (p, MyModel::DROP);
+ *   }
+ *   CallbackTraceSource<Packet,enum TraceType> m_rxSource;
+ *   CallbackTraceSource<Packet,enum TraceType> m_txSource;
+ *   CallbackTraceSource<Packet,enum TraceType> m_dropSource;
+ * };
+ * \endcode
+ * These 3 new sources can be connected easily to a new trace sink:
+ * \code
+ * void ASimpleTraceSink (const TraceContext &context, const Packet &packet, enum MyModel::TraceType type)
+ * {
+ *   // here, read the "type" argument
+ * }
+ * \endcode
+ *
+ * This solution works but it makes it impossible to connect a single trace sink to a set
+ * of trace sources which represent "rx" events in different NetDevice objects since
+ * each of them will define a different enum type with different values: since the
+ * trace sink signature must match exactly the trace source signature, it is impossible
+ * to connect at the same time to all "rx" events of different NetDevice.
+ *
+ * \subsection AdvancedTraceContextFancySolution The more complex and generic solution
+ *
+ * There is, hopefully, a way to get the best of both worlds, that is, to allow a
+ * user to connect to a lot of trace source events of the same kind but coming from different
+ * implementations and to allow the user to differentiate between these different
+ * implementations.
+ *
+ * Rather than define an adhoc enum type with a list of trace sources, you can also
+ * define a new ns3::TraceContextElement for your source sources. For example, if you
+ * define a new MyModelTraceType class which contains the type of trace, your users can
+ * then write trace sink code which looks like this:
+ * \code
+ * void AFancyTraceSink (const TraceContext &context, const Packet &packet)
+ * {
+ *   MyModelTraceType type;
+ *   if (context.GetElement (type))
+ *     {
+ *       switch (type.Get ())
+ *         {
+ *         case MyModelTraceType::RX:
+ *           std::cout << "rx" << std::endl;
+ *           break;
+ *         case MyModelTraceType::TX:
+ *           std::cout << "tx" << std::endl;
+ *           break;
+ *         case MyModelTraceType::DROP:
+ *           std::cout << "drop" << std::endl;
+ *           break;
+ *         }
+ *     }
+ * }
+ * \endcode
+ *
+ * Of course, since the type of trace is stored in the TraceContext, your users can
+ * also take the shortcut which uses the printing functionality of the TraceContext:
+ * \code
+ * void ALessFancyTraceSink (const TraceContext &context, const Packet &packet)
+ * {
+ *   std::cout << "context=\"" << context << "\" packet: " << packet << std::endl;
+ * }
+ * \endcode
+ * which will generate something like the following when the trace source comes
+ * from MyModel:
+ * \code
+ * context="my-model-rx" packet: ...
+ * \endcode
+ *
+ * The first step to achieve this is to define and implement a new
+ * subclass of the ns3::TraceContextElement base class. The exact list of
+ * public methods which must be implemented is described in the API
+ * documentation of the ns3::TraceContextElement class. 
+ * \code
+ * class MyModelTraceType : public TraceContextElement
+ * {
+ * public:
+ *   enum Type {
+ *     RX,
+ *     TX,
+ *     DROP
+ *   };
+ *   // called from MyModel::GetTraceResolver
+ *   MyModelTraceType (enum Type type);
+ *   // called from trace sink
+ *   enum Type Get (void) const;
+ *   // needed by the tracing subsystem
+ *   static uint16_t GetUid (void);
+ *   // needed by the tracing subsystem to
+ *   // print the content of a TraceContext
+ *   void Print (std::ostream &os) const;
+ *   // needed by the tracing subsystem to
+ *   // generate the doxygen documentation.
+ *   std::string GetTypeName (void) const;
+ * private:
+ *   enum Type m_type;
+ * };
+ * \endcode
+ * The implementation does not require much thinking:
+ * \code
+ * MyModelTraceType::MyModelTraceType (enum Type type)
+ *  : m_type (type)
+ * {}
+ * enum Type 
+ * MyModelTraceType::Get (void) const
+ * {
+ *   return m_type;
+ * }
+ * uint16_t 
+ * MyModelTraceType::GetUid (void)
+ * {
+ *   // use protected TraceContextElement::AllocateUid method
+ *   // the input string is used to uniquely identify this new subclass
+ *   static uint16_t uid = AllocateUid<MyModelTraceType> ("ns3::MyModelTraceType");
+ *   return uid;
+ * }
+ * void 
+ * MyModelTraceType::Print (std::ostream &os) const
+ * (
+ *   // this method is invoked by the print function of a TraceContext
+ *   // if it contains an instance of this TraceContextElement.
+ *   switch (m_type) {
+ *     case RX: os << "rx"; break;
+ *     // ...
+ *   }
+ * )
+ * std::string 
+ * MyModelTraceType::GetTypeName (void) const
+ * {
+ *   // This method should return a fully-qualified c++ typename
+ *   // This method is used only for documentation purposes to
+ *   // generate the content of the Trace Source List.
+ *   return "ns3::MyModelTraceType";
+ * }
+ * \endcode
+ *
+ * Once this subclass is implemented, the work is almost completed: you
+ * just need to pass an instance of that class as the last argument of 
+ * the ns3::CompositeTraceResolver::AddSource method as shown below:
+ * \code
+ * Ptr<TraceResolver>
+ * MyModel::GetTraceResolver (void) const
+ * {
+ *   // create an empty trace resolver
+ *   Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
+ *   // register m_rxSource
+ *   resolver->AddSource ("rx", // the name of the trace source in the path string
+ *                        TraceDoc ("some help text to explain the purpose of this trace source",
+ *                                  "Packet", // the type of the first argument to the trace source
+ *                                  "the purpose of the first argument",
+ *                                  "type-of-second-argument", "purpose-of-second-argument"),
+ *                        m_rxSource, // the trace source itself is registered
+ *                        // the TraceContextElement associated to this trace source.
+ *                        MyModelTraceType (MyModelTraceType::RX) 
+ *                       );
+ *   // make sure we include the trace sources implemented in the parent.
+ *   resolver->SetParentResolver (MyParent::GetTraceResolver ());
+ *   return resolver;
+ * }
+ * \endcode
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/csma-broadcast.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,204 @@
+/* -*- 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
+ */
+
+//
+// Example of the sending of a datagram to a broadcast address
+//
+// Network topology
+//     ==============
+//       |          |
+//       n0    n1   n2   
+//       |     |       
+//     ==========
+//
+//   n0 originates UDP broadcast to 255.255.255.255/discard port, which 
+//   is replicated and received on both n1 and n2
+
+#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/log.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/mac48-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"
+#include "ns3/packet-sink.h"
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE ("CsmaBroadcastExample");
+
+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
+  LogComponentEnable ("CsmaBroadcastExample", LOG_LEVEL_INFO);
+
+  LogComponentEnable("Object", LOG_LEVEL_ALL);
+  LogComponentEnable("Queue", LOG_LEVEL_ALL);
+  LogComponentEnable("DropTailQueue", LOG_LEVEL_ALL);
+  LogComponentEnable("Channel", LOG_LEVEL_ALL);
+  LogComponentEnable("CsmaChannel", LOG_LEVEL_ALL);
+  LogComponentEnable("NetDevice", LOG_LEVEL_ALL);
+  LogComponentEnable("CsmaNetDevice", LOG_LEVEL_ALL);
+  LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL);
+  LogComponentEnable("PacketSocket", LOG_LEVEL_ALL);
+  LogComponentEnable("Socket", LOG_LEVEL_ALL);
+  LogComponentEnable("UdpSocket", LOG_LEVEL_ALL);
+  LogComponentEnable("UdpL4Protocol", LOG_LEVEL_ALL);
+  LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL);
+  LogComponentEnable("Ipv4StaticRouting", LOG_LEVEL_ALL);
+  LogComponentEnable("Ipv4Interface", LOG_LEVEL_ALL);
+  LogComponentEnable("ArpIpv4Interface", LOG_LEVEL_ALL);
+  LogComponentEnable("Ipv4LoopbackInterface", LOG_LEVEL_ALL);
+  LogComponentEnable("OnOffApplication", LOG_LEVEL_ALL);
+  // Enable the below logging command to see the packets being received
+  LogComponentEnable("PacketSinkApplication", LOG_LEVEL_ALL);
+#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
+  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
+  CommandLine::Parse (argc, argv);
+
+  // Here, we will explicitly create four nodes.  In more sophisticated
+  // topologies, we could configure a node factory.
+  NS_LOG_INFO ("Create nodes.");
+  Ptr<Node> n0 = Create<InternetNode> ();
+  Ptr<Node> n1 = Create<InternetNode> (); 
+  Ptr<Node> n2 = Create<InternetNode> (); 
+
+  // We create the channels first without any IP addressing information
+  NS_LOG_INFO ("Create channels.");
+  Ptr<CsmaChannel> channel0 = 
+    CsmaTopology::CreateCsmaChannel(
+      DataRate(5000000), MilliSeconds(2));
+
+  // We create the channels first without any IP addressing information
+  Ptr<CsmaChannel> channel1 = 
+    CsmaTopology::CreateCsmaChannel(
+      DataRate(5000000), MilliSeconds(2));
+
+  NS_LOG_INFO ("Build Topology.");
+  uint32_t n0ifIndex0 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n0, channel0, 
+                                         Mac48Address("10:54:23:54:0:50"));
+  uint32_t n0ifIndex1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n0, channel1, 
+                                         Mac48Address("10:54:23:54:0:51"));
+  uint32_t n1ifIndex = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n1, channel0,
+                                         Mac48Address("10:54:23:54:23:51"));
+  uint32_t n2ifIndex = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, channel1,
+                                         Mac48Address("10:54:23:54:23:52"));
+
+  // Later, we add IP addresses.  
+  NS_LOG_INFO ("Assign IP Addresses.");
+  CsmaIpv4Topology::AddIpv4Address (
+      n0, n0ifIndex0, Ipv4Address("10.1.0.1"), Ipv4Mask("255.255.0.0"));
+
+  CsmaIpv4Topology::AddIpv4Address (
+      n1, n1ifIndex, Ipv4Address("10.1.0.2"), Ipv4Mask("255.255.0.0"));
+
+  CsmaIpv4Topology::AddIpv4Address (
+      n0, n0ifIndex1, Ipv4Address("192.168.1.1"), Ipv4Mask("255.255.255.0"));
+  
+  CsmaIpv4Topology::AddIpv4Address (
+      n2, n2ifIndex, Ipv4Address("192.168.1.2"), Ipv4Mask("255.255.255.0"));
+
+  // RFC 863 discard port ("9") indicates packet should be thrown away
+  // by the system.  We allow this silent discard to be overridden
+  // by the PacketSink application.
+  uint16_t port = 9;
+
+  // Create the OnOff application to send UDP datagrams of size
+  // 512 bytes (default) at a rate of 500 Kb/s (default) from n0
+  NS_LOG_INFO ("Create Applications.");
+  Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
+    n0, 
+    InetSocketAddress ("255.255.255.255", port), 
+    "Udp",
+    ConstantVariable(1), 
+    ConstantVariable(0));
+  // Start the application
+  ooff->Start(Seconds(1.0));
+  ooff->Stop (Seconds(10.0));
+  
+  // Create an optional packet sink to receive these packets
+  Ptr<PacketSink> sink = Create<PacketSink> (
+    n1,
+    InetSocketAddress (Ipv4Address::GetAny (), port),
+    "Udp");
+  // Start the sink
+  sink->Start (Seconds (1.0));
+  sink->Stop (Seconds (10.0));
+
+  // Create an optional packet sink to receive these packets
+  sink = Create<PacketSink> (
+    n2,
+    InetSocketAddress (Ipv4Address::GetAny (), port),
+    "Udp");
+  // Start the sink
+  sink->Start (Seconds (1.0));
+  sink->Stop (Seconds (10.0));
+
+  NS_LOG_INFO ("Configure Tracing.");
+  // Configure tracing of all enqueue, dequeue, and NetDevice receive events
+  // Trace output will be sent to the csma-broadcast.tr file
+  AsciiTrace asciitrace ("csma-broadcast.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)
+  PcapTrace pcaptrace ("csma-broadcast.pcap");
+  pcaptrace.TraceAllIp ();
+
+  NS_LOG_INFO ("Run Simulation.");
+  Simulator::Run ();    
+  Simulator::Destroy ();
+  NS_LOG_INFO ("Done.");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/csma-multicast.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,333 @@
+/* -*- 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/log.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/mac48-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"
+#include "ns3/packet-sink.h"
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE ("CsmaMulticastExample");
+
+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
+  LogComponentEnable ("CsmaMulticastExample", LOG_LEVEL_INFO);
+
+  LogComponentEnable("Object", LOG_LEVEL_ALL);
+  LogComponentEnable("Queue", LOG_LEVEL_ALL);
+  LogComponentEnable("DropTailQueue", LOG_LEVEL_ALL);
+  LogComponentEnable("Channel", LOG_LEVEL_ALL);
+  LogComponentEnable("CsmaChannel", LOG_LEVEL_ALL);
+  LogComponentEnable("NetDevice", LOG_LEVEL_ALL);
+  LogComponentEnable("CsmaNetDevice", LOG_LEVEL_ALL);
+  LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL);
+  LogComponentEnable("PacketSocket", LOG_LEVEL_ALL);
+  LogComponentEnable("Socket", LOG_LEVEL_ALL);
+  LogComponentEnable("UdpSocket", LOG_LEVEL_ALL);
+  LogComponentEnable("UdpL4Protocol", LOG_LEVEL_ALL);
+  LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL);
+  LogComponentEnable("Ipv4StaticRouting", LOG_LEVEL_ALL);
+  LogComponentEnable("Ipv4Interface", LOG_LEVEL_ALL);
+  LogComponentEnable("ArpIpv4Interface", LOG_LEVEL_ALL);
+  LogComponentEnable("Ipv4LoopbackInterface", LOG_LEVEL_ALL);
+  LogComponentEnable("OnOffApplication", LOG_LEVEL_ALL);
+  LogComponentEnable("PacketSinkApplication", LOG_LEVEL_ALL);
+  LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_ALL);
+  LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_ALL);
+  LogComponentEnable("PacketSinkApplication", LOG_LEVEL_ALL);
+#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_LOG_INFO ("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_LOG_INFO ("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_LOG_INFO ("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, 
+    Mac48Address("08:00:2e:00:00:00"));
+  uint32_t nd1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n1, lan0, 
+    Mac48Address("08:00:2e:00:00:01"));
+  uint32_t nd2Lan0 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, lan0, 
+    Mac48Address("08:00:2e:00:00:02"));
+
+  uint32_t nd2Lan1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, lan1, 
+    Mac48Address("08:00:2e:00:00:03"));
+  uint32_t nd3 __attribute__ ((unused)) = 
+    CsmaIpv4Topology::AddIpv4CsmaNetDevice (n3, lan1, 
+    Mac48Address("08:00:2e:00:00:04"));
+  uint32_t nd4 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n4, lan1, 
+    Mac48Address("08:00:2e:00:00:05"));
+
+  NS_LOG_INFO ("nd0 = " << nd0);
+  NS_LOG_INFO ("nd1 = " << nd1);
+  NS_LOG_INFO ("nd2Lan0 = " << nd2Lan0);
+  NS_LOG_INFO ("nd2Lan1 = " << nd2Lan1);
+  NS_LOG_INFO ("nd3 = " << nd3);
+  NS_LOG_INFO ("nd4 = " << nd3);
+//
+// We've got the "hardware" in place.  Now we need to add IP addresses.
+//
+  NS_LOG_INFO ("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_LOG_INFO ("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_LOG_INFO ("Create Applications.");
+
+  uint16_t port = 9;   // Discard port (RFC 863)
+
+  // Configure a multicast packet generator that generates a packet
+  // every few seconds
+  Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
+    n0, 
+    InetSocketAddress (multicastGroup, port), 
+    "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.));
+
+  // Create an optional packet sink to receive these packets
+  // If you enable logging on this (above) it will print a log statement
+  // for every packet received
+  Ptr<PacketSink> sink = Create<PacketSink> (
+    n4,
+    InetSocketAddress (Ipv4Address::GetAny (), port),
+    "Udp");
+  // Start the sink
+  sink->Start (Seconds (1.0));
+  sink->Stop (Seconds (10.0));
+
+//
+// Configure tracing of all enqueue, dequeue, and NetDevice receive events.
+// Trace output will be sent to the file "csma-multicast.tr"
+//
+  NS_LOG_INFO ("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_LOG_INFO ("Run Simulation.");
+  Simulator::Run ();
+  Simulator::Destroy ();
+  NS_LOG_INFO ("Done.");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/csma-one-subnet.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,215 @@
+/* -*- 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
+//
+//       n0    n1   n2   n3
+//       |     |    |    |
+//       =================
+//              LAN
+//
+// - 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 "ns3/command-line.h"
+#include "ns3/default-value.h"
+#include "ns3/ptr.h"
+#include "ns3/random-variable.h"
+#include "ns3/log.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/mac48-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_LOG_COMPONENT_DEFINE ("CsmaOneSubnetExample");
+
+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 
+  LogComponentEnable ("CsmaOneSubnetExample", LOG_LEVEL_INFO);
+
+  LogComponentEnable("Object", LOG_LEVEL_ALL);
+  LogComponentEnable("Queue", LOG_LEVEL_ALL);
+  LogComponentEnable("DropTailQueue", LOG_LEVEL_ALL);
+  LogComponentEnable("Channel", LOG_LEVEL_ALL);
+  LogComponentEnable("CsmaChannel", LOG_LEVEL_ALL);
+  LogComponentEnable("NetDevice", LOG_LEVEL_ALL);
+  LogComponentEnable("CsmaNetDevice", LOG_LEVEL_ALL);
+  LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL);
+  LogComponentEnable("PacketSocket", LOG_LEVEL_ALL);
+  LogComponentEnable("Socket", LOG_LEVEL_ALL);
+  LogComponentEnable("UdpSocket", LOG_LEVEL_ALL);
+  LogComponentEnable("UdpL4Protocol", LOG_LEVEL_ALL);
+  LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL);
+  LogComponentEnable("Ipv4StaticRouting", LOG_LEVEL_ALL);
+  LogComponentEnable("Ipv4Interface", LOG_LEVEL_ALL);
+  LogComponentEnable("ArpIpv4Interface", LOG_LEVEL_ALL);
+  LogComponentEnable("Ipv4LoopbackInterface", LOG_LEVEL_ALL);
+  LogComponentEnable("OnOffApplication", LOG_LEVEL_ALL);
+  LogComponentEnable("PacketSinkApplication", LOG_LEVEL_ALL);
+  LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_ALL);
+  LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_ALL);
+#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_LOG_INFO ("Create nodes.");
+  Ptr<Node> n0 = Create<InternetNode> ();
+  Ptr<Node> n1 = Create<InternetNode> (); 
+  Ptr<Node> n2 = Create<InternetNode> (); 
+  Ptr<Node> n3 = Create<InternetNode> ();
+
+  NS_LOG_INFO ("Create channels.");
+//
+// Explicitly create the channels required by the topology (shown above).
+//
+  Ptr<CsmaChannel> lan = CsmaTopology::CreateCsmaChannel(
+    DataRate(5000000), MilliSeconds(2));
+
+  NS_LOG_INFO ("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, 
+    Mac48Address("08:00:2e:00:00:00"));
+
+  uint32_t nd1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n1, lan, 
+    Mac48Address("08:00:2e:00:00:01"));
+
+  uint32_t nd2 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, lan, 
+    Mac48Address("08:00:2e:00:00:02"));
+
+  uint32_t nd3 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n3, lan, 
+    Mac48Address("08:00:2e:00:00:03"));
+//
+// We've got the "hardware" in place.  Now we need to add IP addresses.
+//
+  NS_LOG_INFO ("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 (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, 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_LOG_INFO ("Create Applications.");
+  uint16_t port = 9;   // Discard port (RFC 863)
+  Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
+    n0, 
+    InetSocketAddress ("10.1.1.2", port), 
+    "Udp",
+    ConstantVariable(1), 
+    ConstantVariable(0));
+//
+// 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
+//
+  ooff = Create<OnOffApplication> (
+    n3, 
+    InetSocketAddress ("10.1.1.1", port), 
+    "Udp",
+    ConstantVariable(1), 
+    ConstantVariable(0));
+
+  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 file "csma-one-subnet.tr"
+//
+   NS_LOG_INFO ("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:
+//     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_LOG_INFO ("Run Simulation.");
+  Simulator::Run ();
+  Simulator::Destroy ();
+  NS_LOG_INFO ("Done.");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/csma-packet-socket.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,169 @@
+/* -*- 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
+ */
+
+// Port of ns-2/tcl/ex/simple.tcl to ns-3
+//
+// Network topology
+//
+//       n0    n1   n2   n3
+//       |     |    |    |
+//     =====================
+//
+// - 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)
+// - 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/log.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/mac48-address.h"
+#include "ns3/packet-socket-address.h"
+#include "ns3/socket.h"
+#include "ns3/onoff-application.h"
+#include "ns3/queue.h"
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE ("CsmaPacketSocketExample");
+
+static Ptr<CsmaNetDevice>
+CreateCsmaDevice (Ptr<Node> node, Ptr<CsmaChannel> channel)
+{
+  Ptr<CsmaNetDevice> device = Create<CsmaNetDevice> (node);
+  device->Attach (channel);
+  Ptr<Queue> queue = Queue::CreateDefault ();
+  device->AddQueue (queue);
+  return device;
+}
+
+int
+main (int argc, char *argv[])
+{
+#if 0 
+  LogComponentEnable ("CsmaPacketSocketExample", LOG_LEVEL_INFO);
+
+  LogComponentEnable("Object", LOG_LEVEL_ALL);
+  LogComponentEnable("Queue", LOG_LEVEL_ALL);
+  LogComponentEnable("DropTailQueue", LOG_LEVEL_ALL);
+  LogComponentEnable("Channel", LOG_LEVEL_ALL);
+  LogComponentEnable("CsmaChannel", LOG_LEVEL_ALL);
+  LogComponentEnable("NetDevice", LOG_LEVEL_ALL);
+  LogComponentEnable("CsmaNetDevice", LOG_LEVEL_ALL);
+  LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL);
+  LogComponentEnable("PacketSocket", LOG_LEVEL_ALL);
+  LogComponentEnable("Socket", LOG_LEVEL_ALL);
+  LogComponentEnable("UdpSocket", LOG_LEVEL_ALL);
+  LogComponentEnable("UdpL4Protocol", LOG_LEVEL_ALL);
+  LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL);
+  LogComponentEnable("Ipv4StaticRouting", LOG_LEVEL_ALL);
+  LogComponentEnable("Ipv4Interface", LOG_LEVEL_ALL);
+  LogComponentEnable("ArpIpv4Interface", LOG_LEVEL_ALL);
+  LogComponentEnable("Ipv4LoopbackInterface", LOG_LEVEL_ALL);
+  LogComponentEnable("OnOffApplication", LOG_LEVEL_ALL);
+  LogComponentEnable("PacketSinkApplication", LOG_LEVEL_ALL);
+  LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_ALL);
+  LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_ALL);
+#endif
+
+  CommandLine::Parse (argc, argv);
+
+  // Here, we will explicitly create four nodes.  In more sophisticated
+  // topologies, we could configure a node factory.
+  NS_LOG_INFO ("Create nodes.");
+  Ptr<Node> n0 = Create<Node> ();
+  Ptr<Node> n1 = Create<Node> (); 
+  Ptr<Node> n2 = Create<Node> (); 
+  Ptr<Node> n3 = Create<Node> ();
+
+  // create the shared medium used by all csma devices.
+  NS_LOG_INFO ("Create channels.");
+  Ptr<CsmaChannel> channel = Create<CsmaChannel> (DataRate(5000000), MilliSeconds(2));
+
+  // use a helper function to connect our nodes to the shared channel.
+  NS_LOG_INFO ("Build Topology.");
+  Ptr<NetDevice> n0If = CreateCsmaDevice (n0, channel);
+  Ptr<NetDevice> n1If = CreateCsmaDevice (n1, channel);
+  Ptr<NetDevice> n2If = CreateCsmaDevice (n2, channel);
+  Ptr<NetDevice> n3If = CreateCsmaDevice (n3, channel);
+
+  // create the address which identifies n1 from n0
+  PacketSocketAddress n0ToN1;
+  n0ToN1.SetSingleDevice (n0If->GetIfIndex ());      // set outgoing interface for outgoing packets
+  n0ToN1.SetPhysicalAddress (n1If->GetAddress ()); // set destination address for outgoing packets
+  n0ToN1.SetProtocol (2);            // set arbitrary protocol for outgoing packets
+
+  // create the address which identifies n0 from n3
+  PacketSocketAddress n3ToN0;
+  n3ToN0.SetSingleDevice (n3If->GetIfIndex ());
+  n3ToN0.SetPhysicalAddress (n0If->GetAddress ());
+  n3ToN0.SetProtocol (3);
+  
+  // Create the OnOff application to send raw datagrams of size
+  // 210 bytes at a rate of 448 Kb/s
+  // from n0 to n1
+  NS_LOG_INFO ("Create Applications.");
+  Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
+    n0, 
+    n0ToN1,
+    "Packet",
+    ConstantVariable(1), 
+    ConstantVariable(0));
+  // Start the application
+  ooff->Start(Seconds(1.0));
+  ooff->Stop (Seconds(10.0));
+
+  // Create a similar flow from n3 to n0, starting at time 1.1 seconds
+  ooff = Create<OnOffApplication> (
+    n3, 
+    n3ToN0,
+    "Packet",
+    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-packet-socket.tr file
+  NS_LOG_INFO ("Configure Tracing.");
+  AsciiTrace asciitrace ("csma-packet-socket.tr");
+  asciitrace.TraceAllNetDeviceRx ();
+  asciitrace.TraceAllQueues ();
+
+  NS_LOG_INFO ("Run Simulation.");
+  Simulator::Run ();
+  Simulator::Destroy ();
+  NS_LOG_INFO ("Done.");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/mixed-global-routing.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,224 @@
+/* -*- 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
+ *
+ */
+
+// This script exercises global routing code in a mixed point-to-point
+// and csma/cd environment
+//
+// Network topology
+//
+//  n0
+//     \ p-p
+//      \          (shared csma/cd)
+//       n2 -------------------------n3
+//      /            |        | 
+//     / p-p        n4        n5 ---------- n6
+//   n1                             p-p
+//
+// - CBR/UDP flows from n0 to n6
+// - Tracing of queues and packet receptions to file "mixed-global-routing.tr"
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <cassert>
+
+#include "ns3/log.h"
+
+#include "ns3/command-line.h"
+#include "ns3/default-value.h"
+#include "ns3/ptr.h"
+#include "ns3/random-variable.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/point-to-point-channel.h"
+#include "ns3/point-to-point-net-device.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/mac48-address.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/ipv4.h"
+#include "ns3/socket.h"
+#include "ns3/inet-socket-address.h"
+#include "ns3/ipv4-route.h"
+#include "ns3/point-to-point-topology.h"
+#include "ns3/onoff-application.h"
+#include "ns3/global-route-manager.h"
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE ("MixedGlobalRoutingExample");
+
+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 
+  LogComponentEnable ("MixedGlobalRoutingExample", LOG_LEVEL_INFO);
+
+  LogComponentEnable("Object", LOG_LEVEL_ALL);
+  LogComponentEnable("Queue", LOG_LEVEL_ALL);
+  LogComponentEnable("DropTailQueue", LOG_LEVEL_ALL);
+  LogComponentEnable("Channel", LOG_LEVEL_ALL);
+  LogComponentEnable("CsmaChannel", LOG_LEVEL_ALL);
+  LogComponentEnable("NetDevice", LOG_LEVEL_ALL);
+  LogComponentEnable("CsmaNetDevice", LOG_LEVEL_ALL);
+  LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL);
+  LogComponentEnable("PacketSocket", LOG_LEVEL_ALL);
+  LogComponentEnable("Socket", LOG_LEVEL_ALL);
+  LogComponentEnable("UdpSocket", LOG_LEVEL_ALL);
+  LogComponentEnable("UdpL4Protocol", LOG_LEVEL_ALL);
+  LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL);
+  LogComponentEnable("Ipv4StaticRouting", LOG_LEVEL_ALL);
+  LogComponentEnable("Ipv4Interface", LOG_LEVEL_ALL);
+  LogComponentEnable("ArpIpv4Interface", LOG_LEVEL_ALL);
+  LogComponentEnable("Ipv4LoopbackInterface", LOG_LEVEL_ALL);
+  LogComponentEnable("OnOffApplication", LOG_LEVEL_ALL);
+  LogComponentEnable("PacketSinkApplication", LOG_LEVEL_ALL);
+  LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_ALL);
+  LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_ALL);
+#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 DefaultValue::Bind command tells the queue factory which 
+  // class to instantiate, when the queue factory is invoked in the 
+  // topology code
+  DefaultValue::Bind ("Queue", "DropTailQueue");
+
+  DefaultValue::Bind ("OnOffApplicationPacketSize", "210");
+  DefaultValue::Bind ("OnOffApplicationDataRate", "448kb/s");
+
+  //DefaultValue::Bind ("DropTailQueue::m_maxPackets", 30);   
+
+  // Allow the user to override any of the defaults and the above
+  // Bind ()s at run-time, via command-line arguments
+  CommandLine::Parse (argc, argv);
+
+  NS_LOG_INFO ("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> (); 
+  Ptr<Node> n5 = Create<InternetNode> (); 
+  Ptr<Node> n6 = Create<InternetNode> ();
+
+  // We create the channels first without any IP addressing information
+  NS_LOG_INFO ("Create channels.");
+  Ptr<PointToPointChannel> channel0 = 
+    PointToPointTopology::AddPointToPointLink (
+      n0, n2, DataRate (5000000), MilliSeconds (2));
+
+  Ptr<PointToPointChannel> channel1 = 
+    PointToPointTopology::AddPointToPointLink (
+      n1, n2, DataRate (5000000), MilliSeconds (2));
+  
+  Ptr<PointToPointChannel> channel2 = 
+    PointToPointTopology::AddPointToPointLink (
+      n5, n6, DataRate (1500000), MilliSeconds (10));
+
+  // We create the channels first without any IP addressing information
+  Ptr<CsmaChannel> channelc0 = 
+    CsmaTopology::CreateCsmaChannel(
+      DataRate(5000000), MilliSeconds(2));
+
+  NS_LOG_INFO ("Build Topology.");
+  uint32_t n2ifIndex = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, channelc0,
+                                         Mac48Address("10:54:23:54:23:50"));
+  uint32_t n3ifIndex = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n3, channelc0,
+                                         Mac48Address("10:54:23:54:23:51"));
+  uint32_t n4ifIndex = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n4, channelc0,
+                                         Mac48Address("10:54:23:54:23:52"));
+  uint32_t n5ifIndex = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n5, channelc0,
+                                         Mac48Address("10:54:23:54:23:53"));
+
+  // Later, we add IP addresses.  
+  NS_LOG_INFO ("Assign IP Addresses.");
+  PointToPointTopology::AddIpv4Addresses (
+      channel0, n0, Ipv4Address ("10.1.1.1"),
+      n2, Ipv4Address ("10.1.1.2"));
+  
+  PointToPointTopology::AddIpv4Addresses (
+      channel1, n1, Ipv4Address ("10.1.2.1"),
+      n2, Ipv4Address ("10.1.2.2"));
+  
+  PointToPointTopology::AddIpv4Addresses (
+      channel2, n5, Ipv4Address ("10.1.3.1"),
+      n6, Ipv4Address ("10.1.3.2"));
+
+  CsmaIpv4Topology::AddIpv4Address (
+      n2, n2ifIndex, Ipv4Address("10.250.1.1"), Ipv4Mask("255.255.255.0"));
+
+  CsmaIpv4Topology::AddIpv4Address (
+      n3, n3ifIndex, Ipv4Address("10.250.1.2"), Ipv4Mask("255.255.255.0"));
+  
+  CsmaIpv4Topology::AddIpv4Address (
+      n4, n4ifIndex, Ipv4Address("10.250.1.3"), Ipv4Mask("255.255.255.0"));
+  
+  CsmaIpv4Topology::AddIpv4Address (
+      n5, n5ifIndex, Ipv4Address("10.250.1.4"), Ipv4Mask("255.255.255.0"));
+
+  // Create router nodes, initialize routing database and set up the routing
+  // tables in the nodes.
+  GlobalRouteManager::PopulateRoutingTables ();
+
+  // Create the OnOff application to send UDP datagrams of size
+  // 210 bytes at a rate of 448 Kb/s
+  NS_LOG_INFO ("Create Applications.");
+  uint16_t port = 9;   // Discard port (RFC 863)
+  Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
+    n0, 
+    InetSocketAddress ("10.1.3.2", port), 
+    "Udp",
+    ConstantVariable (1), 
+    ConstantVariable (0),
+    DataRate("300bps"),
+    50);
+  // Start the application
+  ooff->Start (Seconds (1.0));
+  ooff->Stop (Seconds (10.0));
+
+  // Configure tracing of all enqueue, dequeue, and NetDevice receive events
+  // Trace output will be sent to the simple-global-routing.tr file
+  NS_LOG_INFO ("Configure Tracing.");
+  AsciiTrace asciitrace ("mixed-global-routing.tr");
+  asciitrace.TraceAllQueues ();
+  asciitrace.TraceAllNetDeviceRx ();
+
+  // Also configure some tcpdump traces; each interface will be traced
+  // The output files will be named simple-p2p.pcap-<nodeId>-<interfaceId>
+  // and can be read by the "tcpdump -r" command (use "-tt" option to
+  // display timestamps correctly)
+  PcapTrace pcaptrace ("mixed-global-routing.pcap");
+  pcaptrace.TraceAllIp ();
+
+  NS_LOG_INFO ("Run Simulation.");
+  Simulator::Run ();
+  Simulator::Destroy ();
+  NS_LOG_INFO ("Done.");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/simple-global-routing.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,226 @@
+/* -*- 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
+ *
+ * ns-2 simple.tcl script (ported from ns-2)
+ * Originally authored by Steve McCanne, 12/19/1996
+ */
+
+// Port of ns-2/tcl/ex/simple.tcl to ns-3
+//
+// Network topology
+//
+//  n0
+//     \ 5 Mb/s, 2ms
+//      \          1.5Mb/s, 10ms
+//       n2 -------------------------n3
+//      /
+//     / 5 Mb/s, 2ms
+//   n1
+//
+// - all links are point-to-point links with indicated one-way BW/delay
+// - CBR/UDP flows from n0 to n3, and from n3 to n1
+// - FTP/TCP flow from n0 to n3, starting at time 1.2 to time 1.35 sec.
+// - UDP packet size of 210 bytes, with per-packet interval 0.00375 sec.
+//   (i.e., DataRate of 448,000 bps)
+// - DropTail queues 
+// - Tracing of queues and packet receptions to file "simple-global-routing.tr"
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <cassert>
+
+#include "ns3/log.h"
+
+#include "ns3/command-line.h"
+#include "ns3/default-value.h"
+#include "ns3/ptr.h"
+#include "ns3/random-variable.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/point-to-point-channel.h"
+#include "ns3/point-to-point-net-device.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/ipv4.h"
+#include "ns3/socket.h"
+#include "ns3/inet-socket-address.h"
+#include "ns3/ipv4-route.h"
+#include "ns3/point-to-point-topology.h"
+#include "ns3/onoff-application.h"
+#include "ns3/packet-sink.h"
+#include "ns3/global-route-manager.h"
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE ("SimpleGlobalRoutingExample");
+
+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 
+  LogComponentEnable ("SimpleGlobalRoutingExample", LOG_LEVEL_INFO);
+
+  LogComponentEnable("Object", LOG_LEVEL_ALL);
+  LogComponentEnable("Queue", LOG_LEVEL_ALL);
+  LogComponentEnable("DropTailQueue", LOG_LEVEL_ALL);
+  LogComponentEnable("Channel", LOG_LEVEL_ALL);
+  LogComponentEnable("CsmaChannel", LOG_LEVEL_ALL);
+  LogComponentEnable("NetDevice", LOG_LEVEL_ALL);
+  LogComponentEnable("CsmaNetDevice", LOG_LEVEL_ALL);
+  LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL);
+  LogComponentEnable("PacketSocket", LOG_LEVEL_ALL);
+  LogComponentEnable("Socket", LOG_LEVEL_ALL);
+  LogComponentEnable("UdpSocket", LOG_LEVEL_ALL);
+  LogComponentEnable("UdpL4Protocol", LOG_LEVEL_ALL);
+  LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL);
+  LogComponentEnable("Ipv4StaticRouting", LOG_LEVEL_ALL);
+  LogComponentEnable("Ipv4Interface", LOG_LEVEL_ALL);
+  LogComponentEnable("ArpIpv4Interface", LOG_LEVEL_ALL);
+  LogComponentEnable("Ipv4LoopbackInterface", LOG_LEVEL_ALL);
+  LogComponentEnable("OnOffApplication", LOG_LEVEL_ALL);
+  LogComponentEnable("PacketSinkApplication", LOG_LEVEL_ALL);
+  LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_ALL);
+  LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_ALL);
+#endif
+  // Set up some default values for the simulation.  Use the 
+  // DefaultValue::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
+  DefaultValue::Bind ("Queue", "DropTailQueue");
+
+  DefaultValue::Bind ("OnOffApplicationPacketSize", "210");
+  DefaultValue::Bind ("OnOffApplicationDataRate", "448kb/s");
+
+  //DefaultValue::Bind ("DropTailQueue::m_maxPackets", 30);   
+
+  // Allow the user to override any of the defaults and the above
+  // DefaultValue::Bind ()s 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.
+  NS_LOG_INFO ("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_LOG_INFO ("Create channels.");
+  Ptr<PointToPointChannel> channel0 = 
+    PointToPointTopology::AddPointToPointLink (
+      n0, n2, DataRate (5000000), MilliSeconds (2));
+
+  Ptr<PointToPointChannel> channel1 = 
+    PointToPointTopology::AddPointToPointLink (
+      n1, n2, DataRate (5000000), MilliSeconds (2));
+  
+  Ptr<PointToPointChannel> channel2 = 
+    PointToPointTopology::AddPointToPointLink (
+      n2, n3, DataRate (1500000), MilliSeconds (10));
+  
+  // Later, we add IP addresses.  
+  NS_LOG_INFO ("Assign IP Addresses.");
+  PointToPointTopology::AddIpv4Addresses (
+      channel0, n0, Ipv4Address ("10.1.1.1"),
+      n2, Ipv4Address ("10.1.1.2"));
+  
+  PointToPointTopology::AddIpv4Addresses (
+      channel1, n1, Ipv4Address ("10.1.2.1"),
+      n2, Ipv4Address ("10.1.2.2"));
+  
+  PointToPointTopology::AddIpv4Addresses (
+      channel2, n2, Ipv4Address ("10.1.3.1"),
+      n3, Ipv4Address ("10.1.3.2"));
+
+  // Create router nodes, initialize routing database and set up the routing
+  // tables in the nodes.
+  GlobalRouteManager::PopulateRoutingTables ();
+
+  // Create the OnOff application to send UDP datagrams of size
+  // 210 bytes at a rate of 448 Kb/s
+  NS_LOG_INFO ("Create Applications.");
+  uint16_t port = 9;   // Discard port (RFC 863)
+  Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
+    n0, 
+    InetSocketAddress ("10.1.3.2", port), 
+    "Udp",
+    ConstantVariable (1), 
+    ConstantVariable (0));
+  // Start the application
+  ooff->Start (Seconds (1.0));
+  ooff->Stop (Seconds (10.0));
+
+  // Create a packet sink to receive these packets
+  // The last argument "true" disables output from the Receive callback
+  Ptr<PacketSink> sink = Create<PacketSink> (
+    n3, 
+    InetSocketAddress (Ipv4Address::GetAny (), port), 
+    "Udp");
+  // Start the sink
+  sink->Start (Seconds (1.0));
+  sink->Stop (Seconds (10.0));
+
+  // Create a similar flow from n3 to n1, starting at time 1.1 seconds
+  ooff = Create<OnOffApplication> (
+    n3, 
+    InetSocketAddress ("10.1.2.1", port),
+    "Udp",
+    ConstantVariable (1), 
+    ConstantVariable (0));
+  // Start the application
+  ooff->Start (Seconds (1.1));
+  ooff->Stop (Seconds (10.0));
+
+  // Create a packet sink to receive these packets
+  sink = Create<PacketSink> (
+    n1, 
+    InetSocketAddress (Ipv4Address::GetAny (), port), 
+    "Udp");
+  // Start the sink
+  sink->Start (Seconds (1.1));
+  sink->Stop (Seconds (10.0));
+
+  // Configure tracing of all enqueue, dequeue, and NetDevice receive events
+  // Trace output will be sent to the simple-global-routing.tr file
+  NS_LOG_INFO ("Configure Tracing.");
+  AsciiTrace asciitrace ("simple-global-routing.tr");
+  asciitrace.TraceAllQueues ();
+  asciitrace.TraceAllNetDeviceRx ();
+
+  // Also configure some tcpdump traces; each interface will be traced
+  // The output files will be named simple-p2p.pcap-<nodeId>-<interfaceId>
+  // and can be read by the "tcpdump -r" command (use "-tt" option to
+  // display timestamps correctly)
+  PcapTrace pcaptrace ("simple-global-routing.pcap");
+  pcaptrace.TraceAllIp ();
+
+  NS_LOG_INFO ("Run Simulation.");
+  Simulator::Run ();
+  Simulator::Destroy ();
+  NS_LOG_INFO ("Done.");
+
+  return 0;
+}
--- a/examples/simple-p2p.cc	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,191 +0,0 @@
-/* -*- 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
- *
- * ns-2 simple.tcl script (ported from ns-2)
- * Originally authored by Steve McCanne, 12/19/1996
- */
-
-// Port of ns-2/tcl/ex/simple.tcl to ns-3
-//
-// Network topology
-//
-//  n0
-//     \ 5 Mb/s, 2ms
-//      \          1.5Mb/s, 10ms
-//       n2 -------------------------n3
-//      /
-//     / 5 Mb/s, 2ms
-//   n1
-//
-// - all links are p2p links with indicated one-way BW/delay
-// - CBR/UDP flows from n0 to n3, and from n3 to n1
-// - FTP/TCP flow from n0 to n3, starting at time 1.2 to time 1.35 sec.
-// - UDP packet size of 210 bytes, with per-packet interval 0.00375 sec.
-//   (i.e., DataRate of 448,000 bps)
-// - DropTail queues 
-// - Tracing of queues and packet receptions to file "simple-p2p.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/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/p2p-channel.h"
-#include "ns3/p2p-net-device.h"
-#include "ns3/mac-address.h"
-#include "ns3/ipv4-address.h"
-#include "ns3/ipv4.h"
-#include "ns3/socket.h"
-#include "ns3/ipv4-route.h"
-#include "ns3/p2p-topology.h"
-#include "ns3/onoff-application.h"
-
-using namespace ns3;
-
-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("Object");
-  DebugComponentEnable("Queue");
-  DebugComponentEnable("DropTailQueue");
-  DebugComponentEnable("Channel");
-  DebugComponentEnable("PointToPointChannel");
-  DebugComponentEnable("PointToPointNetDevice");
-#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
-  Bind ("Queue", "DropTailQueue");
-
-  Bind ("OnOffApplicationPacketSize", "210");
-  Bind ("OnOffApplicationDataRate", "448kb/s");
-
-  //Bind ("DropTailQueue::m_maxPackets", 30);   
-
-  // Allow the user to override any of the defaults and the above
-  // Bind()s 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.
-  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<PointToPointChannel> channel0 = 
-    PointToPointTopology::AddPointToPointLink (
-      n0, n2, DataRate(5000000), MilliSeconds(2));
-
-  Ptr<PointToPointChannel> channel1 = 
-    PointToPointTopology::AddPointToPointLink (
-      n1, n2, DataRate(5000000), MilliSeconds(2));
-  
-  Ptr<PointToPointChannel> channel2 = 
-    PointToPointTopology::AddPointToPointLink (
-      n2, n3, DataRate(1500000), MilliSeconds(10));
-  
-  // Later, we add IP addresses.  
-  PointToPointTopology::AddIpv4Addresses (
-      channel0, n0, Ipv4Address("10.1.1.1"),
-      n2, Ipv4Address("10.1.1.2"));
-  
-  PointToPointTopology::AddIpv4Addresses (
-      channel1, n1, Ipv4Address("10.1.2.1"),
-      n2, Ipv4Address("10.1.2.2"));
-  
-  PointToPointTopology::AddIpv4Addresses (
-      channel2, n2, Ipv4Address("10.1.3.1"),
-      n3, Ipv4Address("10.1.3.2"));
-
-  // Finally, we add static routes.  These three steps (Channel and
-  // 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
-  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
-  Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
-    n0, 
-    Ipv4Address("10.1.3.2"), 
-    80, 
-    "Udp",
-    ConstantVariable(1), 
-    ConstantVariable(0));
-  // Start the application
-  ooff->Start(Seconds(1.0));
-  ooff->Stop (Seconds(10.0));
-
-  // Create a similar flow from n3 to n1, starting at time 1.1 seconds
-  ooff = Create<OnOffApplication> (
-    n3, 
-    Ipv4Address("10.1.2.1"), 
-    80, 
-    "Udp",
-    ConstantVariable(1), 
-    ConstantVariable(0));
-  // Start the application
-  ooff->Start(Seconds(1.1));
-  ooff->Stop (Seconds(10.0));
-
-  // Here, finish off packet routing configuration
-  // This will likely set by some global StaticRouting object in the future
-  Ptr<Ipv4> ipv4;
-  ipv4 = n0->QueryInterface<Ipv4> (Ipv4::iid);
-  ipv4->SetDefaultRoute (Ipv4Address ("10.1.1.2"), 1);
-  ipv4 = n3->QueryInterface<Ipv4> (Ipv4::iid);
-  ipv4->SetDefaultRoute (Ipv4Address ("10.1.3.1"), 1);
-  
-  // Configure tracing of all enqueue, dequeue, and NetDevice receive events
-  // Trace output will be sent to the simple-p2p.tr file
-  AsciiTrace asciitrace ("simple-p2p.tr");
-  asciitrace.TraceAllQueues ();
-  asciitrace.TraceAllNetDeviceRx ();
-
-  // Also configure some tcpdump traces; each interface will be traced
-  // The output files will be named simple-p2p.pcap-<nodeId>-<interfaceId>
-  // and can be read by the "tcpdump -r" command (use "-tt" option to
-  // display timestamps correctly)
-  PcapTrace pcaptrace ("simple-p2p.pcap");
-  pcaptrace.TraceAllIp ();
-
-  Simulator::Run ();
-    
-  Simulator::Destroy ();
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/simple-point-to-point.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,233 @@
+/* -*- 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
+ *
+ * ns-2 simple.tcl script (ported from ns-2)
+ * Originally authored by Steve McCanne, 12/19/1996
+ */
+
+// Port of ns-2/tcl/ex/simple.tcl to ns-3
+//
+// Network topology
+//
+//  n0
+//     \ 5 Mb/s, 2ms
+//      \          1.5Mb/s, 10ms
+//       n2 -------------------------n3
+//      /
+//     / 5 Mb/s, 2ms
+//   n1
+//
+// - all links are point-to-point links with indicated one-way BW/delay
+// - CBR/UDP flows from n0 to n3, and from n3 to n1
+// - FTP/TCP flow from n0 to n3, starting at time 1.2 to time 1.35 sec.
+// - UDP packet size of 210 bytes, with per-packet interval 0.00375 sec.
+//   (i.e., DataRate of 448,000 bps)
+// - DropTail queues 
+// - Tracing of queues and packet receptions to file 
+//   "simple-point-to-point.tr"
+
+#include "ns3/log.h"
+#include "ns3/command-line.h"
+#include "ns3/default-value.h"
+#include "ns3/ptr.h"
+#include "ns3/random-variable.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/point-to-point-channel.h"
+#include "ns3/point-to-point-net-device.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/point-to-point-topology.h"
+#include "ns3/onoff-application.h"
+#include "ns3/packet-sink.h"
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE ("SimplePointToPointExample");
+
+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 
+  LogComponentEnable ("SimplePointToPointExample", LOG_LEVEL_INFO);
+
+  LogComponentEnable("Object", LOG_LEVEL_ALL);
+  LogComponentEnable("Queue", LOG_LEVEL_ALL);
+  LogComponentEnable("DropTailQueue", LOG_LEVEL_ALL);
+  LogComponentEnable("Channel", LOG_LEVEL_ALL);
+  LogComponentEnable("CsmaChannel", LOG_LEVEL_ALL);
+  LogComponentEnable("NetDevice", LOG_LEVEL_ALL);
+  LogComponentEnable("CsmaNetDevice", LOG_LEVEL_ALL);
+  LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL);
+  LogComponentEnable("PacketSocket", LOG_LEVEL_ALL);
+  LogComponentEnable("Socket", LOG_LEVEL_ALL);
+  LogComponentEnable("UdpSocket", LOG_LEVEL_ALL);
+  LogComponentEnable("UdpL4Protocol", LOG_LEVEL_ALL);
+  LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL);
+  LogComponentEnable("Ipv4StaticRouting", LOG_LEVEL_ALL);
+  LogComponentEnable("Ipv4Interface", LOG_LEVEL_ALL);
+  LogComponentEnable("ArpIpv4Interface", LOG_LEVEL_ALL);
+  LogComponentEnable("Ipv4LoopbackInterface", LOG_LEVEL_ALL);
+  LogComponentEnable("OnOffApplication", LOG_LEVEL_ALL);
+  LogComponentEnable("PacketSinkApplication", LOG_LEVEL_ALL);
+  LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_ALL);
+  LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_ALL);
+#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
+  DefaultValue::Bind ("Queue", "DropTailQueue");
+
+  DefaultValue::Bind ("OnOffApplicationPacketSize", "210");
+  DefaultValue::Bind ("OnOffApplicationDataRate", "448kb/s");
+
+  //DefaultValue::Bind ("DropTailQueue::m_maxPackets", 30);   
+
+  // Allow the user to override any of the defaults and the above
+  // Bind()s 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.
+  NS_LOG_INFO ("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_LOG_INFO ("Create channels.");
+  Ptr<PointToPointChannel> channel0 = 
+    PointToPointTopology::AddPointToPointLink (
+      n0, n2, DataRate(5000000), MilliSeconds(2));
+
+  Ptr<PointToPointChannel> channel1 = 
+    PointToPointTopology::AddPointToPointLink (
+      n1, n2, DataRate(5000000), MilliSeconds(2));
+  
+  Ptr<PointToPointChannel> channel2 = 
+    PointToPointTopology::AddPointToPointLink (
+      n2, n3, DataRate(1500000), MilliSeconds(10));
+  
+  // Later, we add IP addresses.  
+  NS_LOG_INFO ("Assign IP Addresses.");
+  PointToPointTopology::AddIpv4Addresses (
+      channel0, n0, Ipv4Address("10.1.1.1"),
+      n2, Ipv4Address("10.1.1.2"));
+  
+  PointToPointTopology::AddIpv4Addresses (
+      channel1, n1, Ipv4Address("10.1.2.1"),
+      n2, Ipv4Address("10.1.2.2"));
+  
+  PointToPointTopology::AddIpv4Addresses (
+      channel2, n2, Ipv4Address("10.1.3.1"),
+      n3, Ipv4Address("10.1.3.2"));
+
+  // Finally, we add static routes.  These three steps (Channel and
+  // 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_LOG_INFO ("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_LOG_INFO ("Create Applications.");
+  uint16_t port = 9;   // Discard port (RFC 863)
+  Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
+    n0, 
+    InetSocketAddress ("10.1.3.2", port), 
+    "Udp",
+    ConstantVariable(1), 
+    ConstantVariable(0));
+  // Start the application
+  ooff->Start(Seconds(1.0));
+  ooff->Stop (Seconds(10.0));
+
+  // Create an optional packet sink to receive these packets
+  Ptr<PacketSink> sink = Create<PacketSink> (
+    n3,
+    InetSocketAddress (Ipv4Address::GetAny (), port),
+    "Udp");
+  // Start the sink
+  sink->Start (Seconds (1.0));
+  sink->Stop (Seconds (10.0));
+
+  // Create a similar flow from n3 to n1, starting at time 1.1 seconds
+  ooff = Create<OnOffApplication> (
+    n3, 
+    InetSocketAddress ("10.1.2.1", port), 
+    "Udp",
+    ConstantVariable(1), 
+    ConstantVariable(0));
+  // Start the application
+  ooff->Start(Seconds(1.1));
+  ooff->Stop (Seconds(10.0));
+
+  // Create a packet sink to receive these packets
+  sink = Create<PacketSink> (
+    n1,
+    InetSocketAddress (Ipv4Address::GetAny (), port),
+    "Udp");
+  // Start the sink
+  sink->Start (Seconds (1.1));
+  sink->Stop (Seconds (10.0));
+
+  // Here, finish off packet routing configuration
+  // This will likely set by some global StaticRouting object in the future
+  NS_LOG_INFO ("Set Default Routes.");
+  Ptr<Ipv4> ipv4;
+  ipv4 = n0->QueryInterface<Ipv4> (Ipv4::iid);
+  ipv4->SetDefaultRoute (Ipv4Address ("10.1.1.2"), 1);
+  ipv4 = n3->QueryInterface<Ipv4> (Ipv4::iid);
+  ipv4->SetDefaultRoute (Ipv4Address ("10.1.3.1"), 1);
+  
+  // Configure tracing of all enqueue, dequeue, and NetDevice receive events
+  // Trace output will be sent to the simple-point-to-point.tr file
+  NS_LOG_INFO ("Configure Tracing.");
+  AsciiTrace asciitrace ("simple-point-to-point.tr");
+  asciitrace.TraceAllQueues ();
+  asciitrace.TraceAllNetDeviceRx ();
+
+  // 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)
+  PcapTrace pcaptrace ("simple-point-to-point.pcap");
+  pcaptrace.TraceAllIp ();
+
+  NS_LOG_INFO ("Run Simulation.");
+  Simulator::Run ();    
+  Simulator::Destroy ();
+  NS_LOG_INFO ("Done.");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/udp-echo.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,213 @@
+/* -*- 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
+//
+//       n0    n1   n2   n3
+//       |     |    |    |
+//       =================
+//              LAN
+//
+// - UDP flows from n0 to n1 and back
+// - DropTail queues 
+// - Tracing of queues and packet receptions to file "udp-echo.tr"
+
+#include "ns3/command-line.h"
+#include "ns3/default-value.h"
+#include "ns3/ptr.h"
+#include "ns3/log.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/mac48-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/udp-echo-client.h"
+#include "ns3/udp-echo-server.h"
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE ("UdpEchoExample");
+
+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
+  LogComponentEnable ("UdpEchoExample", LOG_LEVEL_INFO);
+
+  LogComponentEnable("Object", LOG_LEVEL_ALL);
+  LogComponentEnable("Queue", LOG_LEVEL_ALL);
+  LogComponentEnable("DropTailQueue", LOG_LEVEL_ALL);
+  LogComponentEnable("Channel", LOG_LEVEL_ALL);
+  LogComponentEnable("CsmaChannel", LOG_LEVEL_ALL);
+  LogComponentEnable("NetDevice", LOG_LEVEL_ALL);
+  LogComponentEnable("CsmaNetDevice", LOG_LEVEL_ALL);
+  LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL);
+  LogComponentEnable("PacketSocket", LOG_LEVEL_ALL);
+  LogComponentEnable("Socket", LOG_LEVEL_ALL);
+  LogComponentEnable("UdpSocket", LOG_LEVEL_ALL);
+  LogComponentEnable("UdpL4Protocol", LOG_LEVEL_ALL);
+  LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL);
+  LogComponentEnable("Ipv4StaticRouting", LOG_LEVEL_ALL);
+  LogComponentEnable("Ipv4Interface", LOG_LEVEL_ALL);
+  LogComponentEnable("ArpIpv4Interface", LOG_LEVEL_ALL);
+  LogComponentEnable("Ipv4LoopbackInterface", LOG_LEVEL_ALL);
+  LogComponentEnable("OnOffApplication", LOG_LEVEL_ALL);
+  LogComponentEnable("PacketSinkApplication", LOG_LEVEL_ALL);
+  LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_ALL);
+  LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_ALL);
+#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_LOG_INFO ("Create nodes.");
+  Ptr<Node> n0 = Create<InternetNode> ();
+  Ptr<Node> n1 = Create<InternetNode> (); 
+  Ptr<Node> n2 = Create<InternetNode> (); 
+  Ptr<Node> n3 = Create<InternetNode> ();
+
+  NS_LOG_INFO ("Create channels.");
+//
+// Explicitly create the channels required by the topology (shown above).
+//
+  Ptr<CsmaChannel> lan = CsmaTopology::CreateCsmaChannel(
+    DataRate(5000000), MilliSeconds(2));
+
+  NS_LOG_INFO ("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, 
+    Mac48Address("08:00:2e:00:00:00"));
+
+  uint32_t nd1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n1, lan, 
+    Mac48Address("08:00:2e:00:00:01"));
+
+  uint32_t nd2 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, lan, 
+    Mac48Address("08:00:2e:00:00:02"));
+
+  uint32_t nd3 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n3, lan, 
+    Mac48Address("08:00:2e:00:00:03"));
+//
+// We've got the "hardware" in place.  Now we need to add IP addresses.
+//
+  NS_LOG_INFO ("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 (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, nd3, Ipv4Address("10.1.1.4"), 
+    Ipv4Mask("255.255.255.0"));
+
+  NS_LOG_INFO ("Create Applications.");
+//
+// Create a UdpEchoServer application on node one.
+//
+  uint16_t port = 9;  // well-known echo port number
+
+  Ptr<UdpEchoServer> server = Create<UdpEchoServer> (n1, port);
+//
+// Create a UdpEchoClient application to send UDP datagrams from node zero to
+// node one.
+//
+  uint32_t packetSize = 1024;
+  uint32_t maxPacketCount = 1;
+  Time interPacketInterval = Seconds (1.);
+
+  Ptr<UdpEchoClient> client = Create<UdpEchoClient> (n0, "10.1.1.2", port, 
+    maxPacketCount, interPacketInterval, packetSize);
+//
+// Tell the applications when to start and stop.
+//
+  server->Start(Seconds(1.));
+  client->Start(Seconds(2.));
+
+  server->Stop (Seconds(10.));
+  client->Stop (Seconds(10.));
+//
+// Configure tracing of all enqueue, dequeue, and NetDevice receive events.
+// Trace output will be sent to the file "udp-echo.tr"
+//
+  NS_LOG_INFO ("Configure Tracing.");
+  AsciiTrace asciitrace ("udp-echo.tr");
+  asciitrace.TraceAllNetDeviceRx ();
+  asciitrace.TraceAllQueues ();
+//
+// Also configure some tcpdump traces; each interface will be traced.
+// The output files will be named:
+//     udp-echo.pcap-<nodeId>-<interfaceId>
+// and can be read by the "tcpdump -r" command (use "-tt" option to
+// display timestamps correctly)
+//
+  PcapTrace pcaptrace ("udp-echo.pcap");
+  pcaptrace.TraceAllIp ();
+//
+// Now, do the actual simulation.
+//
+  NS_LOG_INFO ("Run Simulation.");
+  Simulator::Run ();
+  Simulator::Destroy ();
+  NS_LOG_INFO ("Done.");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/waf	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,1 @@
+exec "`dirname "$0"`"/../waf "$@"
--- a/examples/wscript	Thu Jul 19 13:17:35 2007 +0200
+++ b/examples/wscript	Fri Sep 28 11:59:46 2007 +0100
@@ -1,13 +1,35 @@
 ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
-import Params
 
 def build(bld):
-    def create_ns_prog(name, source, deps=['core', 'common', 'simulator']):
-        obj = bld.create_obj('cpp', 'program')
-        obj.target = name
-        obj.uselib_local = ["ns3-%s" % dep for dep in deps]
-        obj.source = source
-        return obj
         
-    obj = create_ns_prog('simple-p2p', 'simple-p2p.cc', deps=['p2p', 'internet-node'])
+    obj = bld.create_ns3_program('simple-global-routing',
+        ['point-to-point', 'internet-node', 'global-routing'])
+    obj.source = 'simple-global-routing.cc'
+
+    obj = bld.create_ns3_program('simple-point-to-point',
+        ['point-to-point', 'internet-node'])
+    obj.source = 'simple-point-to-point.cc'
+
+    obj = bld.create_ns3_program('csma-one-subnet',
+        ['csma', 'internet-node'])
+    obj.source = 'csma-one-subnet.cc'
+
+    obj = bld.create_ns3_program('udp-echo',
+        ['csma', 'internet-node'])
+    obj.source = 'udp-echo.cc'
 
+    obj = bld.create_ns3_program('csma-broadcast',
+        ['csma', 'internet-node'])
+    obj.source = 'csma-broadcast.cc'
+
+    obj = bld.create_ns3_program('csma-packet-socket',
+        ['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/samples/main-channel.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/samples/main-channel.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -18,7 +18,7 @@
  */
 
 #include <string>
-#include "ns3/debug.h"
+#include "ns3/log.h"
 #include "ns3/assert.h"
 #include "ns3/packet.h"
 #include "ns3/drop-tail.h"
@@ -27,6 +27,8 @@
 
 using namespace ns3;
 
+NS_LOG_COMPONENT_DEFINE ("ChannelSample");
+
 // ===========================================================================
 // Cook up a simplistic Internet Node
 // ===========================================================================
@@ -48,19 +50,19 @@
 
 FakeInternetNode::FakeInternetNode ()
 {
-  NS_DEBUG_UNCOND("FakeInternetNode::FakeInternetNode ()");
+  NS_LOG_FUNCTION;
 }
 
 FakeInternetNode::~FakeInternetNode ()
 {
-  NS_DEBUG_UNCOND("FakeInternetNode::~FakeInternetNode ()");
+  NS_LOG_FUNCTION;
 }
 
   void
 FakeInternetNode::Doit (void)
 {
-  NS_DEBUG_UNCOND("FakeInternetNode::Doit ()");
-  NS_DEBUG_UNCOND("FakeInternetNode::Doit (): **** Send outbound packet");
+  NS_LOG_FUNCTION;
+  NS_LOG_INFO ("**** Send outbound packet");
   Packet p;
 
   m_dtqOutbound.Enqueue(p);
@@ -70,9 +72,9 @@
   bool
 FakeInternetNode::UpperDoSendUp (Packet &p)
 {
-  NS_DEBUG_UNCOND("FakeInternetNode::UpperDoSendUp (" << &p << ")");
-
-  NS_DEBUG_UNCOND("FakeInternetNode::UpperDoSendUp (): **** Receive inbound packet");
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << &p << ")");
+  NS_LOG_INFO ("**** Receive inbound packet");
   m_dtqInbound.Enqueue(p);
   return m_dtqInbound.Dequeue(p);
 }
@@ -80,7 +82,8 @@
   bool
 FakeInternetNode::UpperDoPull (Packet &p)
 {
-  NS_DEBUG_UNCOND("FakeInternetNode::DoPull (" << &p << ")");
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << &p << ")");
 
   return m_dtqOutbound.Dequeue(p);
 }
@@ -107,29 +110,29 @@
 
 FakePhysicalLayer::FakePhysicalLayer ()
 {
-  NS_DEBUG_UNCOND("FakePhysicalLayer::FakePhysicalLayer ()");
+  NS_LOG_FUNCTION;
 }
 
 FakePhysicalLayer::~FakePhysicalLayer ()
 {
-  NS_DEBUG_UNCOND("FakePhysicalLayer::~FakePhysicalLayer ()");
+  NS_LOG_FUNCTION;
 }
 
   bool
 FakePhysicalLayer::LowerDoNotify (LayerConnectorUpper *upper)
 {
-  NS_DEBUG_UNCOND("FakePhysicalLayer::LowerDoNotify ()");
+  NS_LOG_FUNCTION;
 
   Packet p;
 
-  NS_DEBUG_UNCOND("FakePhysicalLayer::LowerDoNotify (): Starting pull");
+  NS_LOG_LOGIC ("Starting pull");
 
   NS_ASSERT(m_upperPartner);
   m_upperPartner->UpperPull(p);
 
   m_dtqOutbound.Enqueue(p);
 
-  NS_DEBUG_UNCOND("FakePhysicalLayer::LowerDoNotify (): Got bits,  Notify lower");
+  NS_LOG_LOGIC ("Got bits,  Notify lower");
 
   NS_ASSERT(m_lowerPartner);
   return m_lowerPartner->LowerNotify(this);
@@ -138,7 +141,8 @@
   bool
 FakePhysicalLayer::UpperDoSendUp (Packet &p)
 {
-  NS_DEBUG_UNCOND("FakePhysicalLayer::UpperDoSendUp (" << &p << ")");
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << &p << ")");
 
   NS_ASSERT(m_upperPartner);
   return m_upperPartner->UpperSendUp(p);
@@ -147,7 +151,8 @@
   bool
 FakePhysicalLayer::UpperDoPull (Packet &p)
 {
-  NS_DEBUG_UNCOND("FakePhysicalLayer::DoPull (" << &p << ")");
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << &p << ")");
 
   return m_dtqOutbound.Dequeue(p);
 }
@@ -164,24 +169,17 @@
 
 FakeChannel::FakeChannel ()
 {
-  NS_DEBUG_UNCOND("FakeChannel::FakeChannel ()");
+  NS_LOG_FUNCTION;
 }
 
 FakeChannel::~FakeChannel ()
 {
-  NS_DEBUG_UNCOND("FakeChannel::~FakeChannel ()");
+  NS_LOG_FUNCTION;
 }
 
 int main (int argc, char *argv[])
 {
-  NS_DEBUG_UNCOND("Channel Hackorama");
-
-#if 0
-  DebugComponentEnable("Queue");
-  DebugComponentEnable("DropTailQueue");
-  DebugComponentEnable("LayerConnector");
-  DebugComponentEnable("Channel");
-#endif
+  NS_LOG_INFO ("Channel Hackorama");
 
   FakeInternetNode      node1, node2, node3, node4;
   FakePhysicalLayer     phys1, phys2, phys3, phys4;
--- a/samples/main-default-value.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/samples/main-default-value.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -3,7 +3,7 @@
 #include <string>
 #include "ns3/default-value.h"
 #include "ns3/command-line.h"
-#include "ns3/debug.h"
+#include "ns3/log.h"
 
 using namespace ns3;
 
@@ -14,8 +14,8 @@
 // value of the default parameter.  Then as other code require the values of 
 // the defaults, they query them with GetValue() to get the present value.
 static BooleanDefaultValue defaultTestBool1 ("testBool1", "helpBool", true);
-static IntegerDefaultValue<int> defaultTestInt1 ("testInt1", "helpInt1", 33);
-static IntegerDefaultValue<uint32_t> defaultTestInt2 ("testInt2", "helpInt2", 47);
+static NumericDefaultValue<int> defaultTestInt1 ("testInt1", "helpInt1", 33);
+static NumericDefaultValue<uint32_t> defaultTestInt2 ("testInt2", "helpInt2", 47);
 
 // 
 // This test class demonstrates the declaration of variables that
@@ -73,12 +73,12 @@
   // global variable and value (string) to overwrite the default.
   // Here, the default value of 33 for testInt1 is overwritten with 57
   // 
-  Bind("testInt1", "57");
+  DefaultValue::Bind("testInt1", "57");
 
   TestClass* testclass = new TestClass ();
-  NS_DEBUG_UNCOND("TestBool1 default value (" << testclass->m_testBool1 << ")");
-  NS_DEBUG_UNCOND("TestInt1 default value (" << testclass->m_testInt1 << ")");
-  NS_DEBUG_UNCOND("TestInt2 default value (" << testclass->m_testInt2 << ")");
+  NS_LOG_UNCOND("TestBool1 default value (" << testclass->m_testBool1 << ")");
+  NS_LOG_UNCOND("TestInt1 default value (" << testclass->m_testInt1 << ")");
+  NS_LOG_UNCOND("TestInt2 default value (" << testclass->m_testInt2 << ")");
   delete testclass;
 
   return 0;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/samples/main-packet-header.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,124 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+#include "ns3/packet.h"
+#include "ns3/header.h"
+#include <iostream>
+
+using namespace ns3;
+
+/* A sample Header implementation
+ */
+class MyHeader : public Header 
+{
+public:
+  static uint32_t GetUid (void);
+
+  MyHeader ();
+  virtual ~MyHeader ();
+
+  void SetData (uint16_t data);
+  uint16_t GetData (void) const;
+
+  std::string GetName (void) const;
+  void Print (std::ostream &os) const;
+  void Serialize (Buffer::Iterator start) const;
+  uint32_t Deserialize (Buffer::Iterator start);
+  uint32_t GetSerializedSize (void) const;
+private:
+  uint16_t m_data;
+};
+
+MyHeader::MyHeader ()
+{
+  // we must provide a public default constructor, 
+  // implicit or explicit, but never private.
+}
+MyHeader::~MyHeader ()
+{}
+
+uint32_t
+MyHeader::GetUid (void)
+{
+  // This string is used by the internals of the packet
+  // code to keep track of the packet metadata.
+  // You need to make sure that this string is absolutely
+  // unique. The code will detect any duplicate string.
+  static uint32_t uid = AllocateUid<MyHeader> ("MyHeader.test.nsnam.org");
+  return uid;
+}
+
+std::string 
+MyHeader::GetName (void) const
+{
+  // This string is used to identify the type of 
+  // my header by the packet printing routines.
+  return "MYHEADER";
+}
+void 
+MyHeader::Print (std::ostream &os) const
+{
+  // This method is invoked by the packet printing
+  // routines to print the content of my header.
+  os << "data=" << m_data << std::endl;
+}
+uint32_t
+MyHeader::GetSerializedSize (void) const
+{
+  // we reserve 2 bytes for our header.
+  return 2;
+}
+void
+MyHeader::Serialize (Buffer::Iterator start) const
+{
+  // we can serialize two bytes at the start of the buffer.
+  // we write them in network byte order.
+  start.WriteHtonU16 (m_data);
+}
+uint32_t
+MyHeader::Deserialize (Buffer::Iterator start)
+{
+  // we can deserialize two bytes from the start of the buffer.
+  // we read them in network byte order and store them
+  // in host byte order.
+  m_data = start.ReadNtohU16 ();
+
+  // we return the number of bytes effectively read.
+  return 2;
+}
+
+void 
+MyHeader::SetData (uint16_t data)
+{
+  m_data = data;
+}
+uint16_t 
+MyHeader::GetData (void) const
+{
+  return m_data;
+}
+
+
+
+int main (int argc, char *argv[])
+{
+  // instantiate a header.
+  MyHeader sourceHeader;
+  sourceHeader.SetData (2);
+
+  // instantiate a packet
+  Packet p;
+  // and store my header into the packet.
+  p.AddHeader (sourceHeader);
+
+  // print the content of my packet on the standard output.
+  p.Print (std::cout);
+
+  // you can now remove the header from the packet:
+  MyHeader destinationHeader;
+  p.RemoveHeader (destinationHeader);
+
+  // and check that the destination and source
+  // headers contain the same values.
+  NS_ASSERT (sourceHeader.GetData () == destinationHeader.GetData ());
+
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/samples/main-packet-printer.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,184 @@
+/* -*- 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
+ * 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/packet.h"
+#include "ns3/header.h"
+#include "ns3/packet-printer.h"
+#include "ns3/ipv4-header.h"
+#include "ns3/udp-header.h"
+
+using namespace ns3;
+
+// This sample file shows how to use the Packet metadata facility
+//
+// Packets are stored as ``packed'' data structures, to facilitate
+// fragmentation and network emulation.  However, when debugging a program,
+// or for certain tracing applications, it may be convenient to dump out
+// the contents of a packet header in a human-friendly form.
+//
+// To do this, a few things are needed:
+// i) enable the metadata facility (disabled by default, because it causes
+//    a small performance hit 
+// ii) decide on whether you want to use a default or customized (you
+//     provide your own) routine to dump a particular header
+//
+// This sample steps through two routines; one to use the default
+// printing of IPv4 and UDP headers, and one to show a non-default case.
+// There is a lot of emphasis in this sample of how this facility
+// interacts with packet fragmentation.
+
+void DefaultPrint (void)
+{
+  // We create a packet with 1000 bytes of zero payload
+  // and add 3 headers to this packet.
+  Packet p (1000);
+  Ipv4Header ipv4;
+  UdpHeader udp;
+  ipv4.SetSource (Ipv4Address ("192.168.0.1"));
+  ipv4.SetDestination (Ipv4Address ("192.168.0.2"));
+  udp.SetSource (1025);
+  udp.SetDestination (80);
+  udp.SetPayloadSize (1000);
+  p.AddHeader (udp);
+  p.AddHeader (ipv4);
+
+  std::cout << "full packet size=" << p.GetSize () << std::endl;
+  // Here, invoke the default Print routine, directed to std out
+  p.Print (std::cout);
+  std::cout << std::endl;
+
+
+  // Now, we fragment our packet in 3 consecutive pieces.
+  Packet p1 = p.CreateFragment (0, 2);
+  Packet p2 = p.CreateFragment (2, 1000);
+  Packet p3 = p.CreateFragment (1002, 26);
+
+  std::cout << "fragment1" << std::endl;
+  p1.Print (std::cout);
+  std::cout << std::endl;
+  std::cout << "fragment2" << std::endl;
+  p2.Print (std::cout);
+  std::cout << std::endl;
+  std::cout << "fragment3" << std::endl;
+  p3.Print (std::cout);
+  std::cout << std::endl;
+
+  // And, finally, we re-aggregate the 3 consecutive pieces.
+  Packet aggregate = p1;
+  aggregate.AddAtEnd (p2);
+  aggregate.AddAtEnd (p3);
+  std::cout << "aggregated" << std::endl;
+  aggregate.Print (std::cout);
+  std::cout << std::endl;
+}
+
+void
+DoPrintPayload (std::ostream & os,uint32_t packetUid,uint32_t size,
+                struct PacketPrinter::FragmentInformation info)
+{
+  os << "PAYLOAD (size " << size << " trim_start " << info.start << " trim_end " << info.end << ")";
+}
+void 
+DoPrintIpv4Header (std::ostream &os, uint32_t packetUid, uint32_t size, const Ipv4Header *ipv4)
+{
+  os << "IPV4 " << ipv4->GetSource () << " > " << ipv4->GetDestination ();
+}
+void 
+DoPrintIpv4HeaderFragment (std::ostream &os, uint32_t packetUid, uint32_t size,
+                          std::string &name, struct PacketPrinter::FragmentInformation info)
+{
+  os << "IPV4 fragment";
+}
+
+// This function walks through a non-default case.  A few features of
+// the API (defined in common/packet-printer.h) are shown.
+//
+void NonDefaultPrint (void)
+{
+  // create an adhoc packet printer.
+  PacketPrinter printer;
+  // print from first header to last trailer
+  printer.PrintForward ();
+  // set a string separator automatically inserted
+  // between each call to a printing function.
+  printer.SetSeparator (" - ");
+  // set the payload print function
+  printer.SetPayloadPrinter (MakeCallback (&DoPrintPayload));
+  // set the print function for the header type Ipv4Header.
+  printer.SetHeaderPrinter (MakeCallback (&DoPrintIpv4Header),
+                            MakeCallback (&DoPrintIpv4HeaderFragment));
+
+
+  // We create a packet with 1000 bytes of zero payload
+  Packet p (1000);
+  Ipv4Header ipv4;
+  UdpHeader udp;
+  ipv4.SetSource (Ipv4Address ("192.168.0.1"));
+  ipv4.SetDestination (Ipv4Address ("192.168.0.2"));
+  udp.SetSource (1025);
+  udp.SetDestination (80);
+  udp.SetPayloadSize (1000);
+  p.AddHeader (udp);
+  p.AddHeader (ipv4);
+
+  std::cout << "full packet size=" << p.GetSize () << std::endl;
+  p.Print (std::cout, printer);
+  std::cout << std::endl;
+
+
+  // fragment our packet in 3 pieces
+  Packet p1 = p.CreateFragment (0, 2);
+  Packet p2 = p.CreateFragment (2, 1000);
+  Packet p3 = p.CreateFragment (1002, 26);
+  std::cout << "fragment1" << std::endl;
+  p1.Print (std::cout, printer);
+  std::cout << std::endl;
+  std::cout << "fragment2" << std::endl;
+  p2.Print (std::cout, printer);
+  std::cout << std::endl;
+  std::cout << "fragment3" << std::endl;
+  p3.Print (std::cout, printer);
+  std::cout << std::endl;
+
+  // aggregate all 3 fragments of the original packet
+  // to reconstruct a copy of the original packet.
+  Packet aggregate = p1;
+  aggregate.AddAtEnd (p2);
+  aggregate.AddAtEnd (p3);
+  std::cout << "aggregated" << std::endl;
+  aggregate.Print (std::cout, printer);
+  std::cout << std::endl;
+}
+
+
+
+int main (int argc, char *argv[])
+{
+  Packet::EnableMetadata ();
+
+  std::cout << "DefaultPrint()" << std::endl;
+  DefaultPrint ();
+
+  std::cout << std::endl << "NonDefaultPrint()" << std::endl;
+  NonDefaultPrint ();
+
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/samples/main-packet-tag.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,136 @@
+/* -*- 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/tag.h"
+#include "ns3/packet.h"
+#include <iostream>
+
+using namespace ns3;
+
+// define this class in a public header
+class MyTag : public Tag
+{
+public:
+  // we have to define a public constructor
+  MyTag ();
+  // we have to define a public copy constructor
+  MyTag (const MyTag &other);
+  // we have to define a public destructor
+  ~MyTag ();
+  // we have to define a public static GetUid method
+  static uint32_t GetUid (void);
+  // we have to define a public Print method
+  void Print (std::ostream &os) const;
+  // we have to define a public GetSerializedSize method
+  uint32_t GetSerializedSize (void) const;
+  // we have to define a public Serialize method
+  void Serialize (Buffer::Iterator i) const;
+  // we have to define a public Deserialize method
+  uint32_t Deserialize (Buffer::Iterator i);
+  
+  // these are our accessors to our tag structure
+  void SetSimpleValue (uint8_t value);
+  uint8_t GetSimpleValue (void) const;
+private:
+  uint8_t m_simpleValue;
+};
+
+MyTag::MyTag ()
+{}
+MyTag::MyTag (const MyTag &other)
+  : m_simpleValue (other.m_simpleValue)
+{}
+MyTag::~MyTag ()
+{}
+uint32_t 
+MyTag::GetUid (void)
+{
+  // we input a unique string to AllocateUid
+  // to avoid name collisions.
+  static uint32_t uid = AllocateUid<MyTag> ("MyTag.tests.nsnam.org");
+  return uid;
+}
+void 
+MyTag::Print (std::ostream &os) const
+{
+  // print the content of this tag for Packet::PrintTags
+  os << "MyTag=0x" << std::hex << (uint32_t)m_simpleValue << std::dec;
+}
+uint32_t 
+MyTag::GetSerializedSize (void) const
+{
+  // we do not want to deal with parallel simulations
+  // so we return 0.
+  return 0;
+}
+void 
+MyTag::Serialize (Buffer::Iterator i) const
+{
+  // we will never be invoked because we are not doing
+  // parallel simulations so, we assert.
+  NS_ASSERT (false);
+}
+uint32_t
+MyTag::Deserialize (Buffer::Iterator i)
+{
+  // we will never be invoked because we are not doing
+  // parallel simulations so, we assert.
+  NS_ASSERT (false);
+  // theoretically, return the number of bytes read
+  return 0;
+}
+
+
+void 
+MyTag::SetSimpleValue (uint8_t value)
+{
+  m_simpleValue = value;
+}
+uint8_t 
+MyTag::GetSimpleValue (void) const
+{
+  return m_simpleValue;
+}
+
+
+int main (int argc, char *argv[])
+{
+  // create a tag.
+  MyTag tag;
+  tag.SetSimpleValue (0x56);
+
+  // store the tag in a packet.
+  Packet p;
+  p.AddTag (tag);
+
+  // create a copy of the packet
+  Packet aCopy = p;
+
+  // read the tag from the packet copy
+  MyTag tagCopy;
+  p.PeekTag (tagCopy);
+
+  // the copy and the original are the same !
+  NS_ASSERT (tagCopy.GetSimpleValue () == tag.GetSimpleValue ());
+
+  aCopy.PrintTags (std::cout);
+  std::cout << std::endl;
+
+  return 0;
+}
--- a/samples/main-packet.cc	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,97 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-#include "ns3/packet.h"
-#include "ns3/header.h"
-#include <iostream>
-
-using namespace ns3;
-
-/* A sample Header implementation
- */
-class MyHeader : public Header {
-public:
-  MyHeader ();
-  virtual ~MyHeader ();
-
-  void SetData (uint16_t data);
-  uint16_t GetData (void) const;
-private:
-  virtual void PrintTo (std::ostream &os) const;
-  virtual void SerializeTo (Buffer::Iterator start) const;
-  virtual uint32_t DeserializeFrom (Buffer::Iterator start);
-  virtual uint32_t GetSerializedSize (void) const;
-
-  uint16_t m_data;
-};
-
-MyHeader::MyHeader ()
-{}
-MyHeader::~MyHeader ()
-{}
-void 
-MyHeader::PrintTo (std::ostream &os) const
-{
-  os << "MyHeader data=" << m_data << std::endl;
-}
-uint32_t
-MyHeader::GetSerializedSize (void) const
-{
-  return 2;
-}
-void
-MyHeader::SerializeTo (Buffer::Iterator start) const
-{
-  // serialize in head of buffer
-  start.WriteHtonU16 (m_data);
-}
-uint32_t
-MyHeader::DeserializeFrom (Buffer::Iterator start)
-{
-  // deserialize from head of buffer
-  m_data = start.ReadNtohU16 ();
-  return GetSerializedSize ();
-}
-
-void 
-MyHeader::SetData (uint16_t data)
-{
-  m_data = data;
-}
-uint16_t 
-MyHeader::GetData (void) const
-{
-  return m_data;
-}
-
-/* A sample Tag implementation
- */
-struct MyTag {
-  uint16_t m_streamId;
-};
-
-static TagRegistration<struct MyTag> g_MyTagRegistration ("ns3::MyTag", 0);
-
-
-static void
-Receive (Packet p)
-{
-  MyHeader my;
-  p.RemoveHeader (my);
-  std::cout << "received data=" << my.GetData () << std::endl;
-  struct MyTag myTag;
-  p.PeekTag (myTag);
-}
-
-
-int main (int argc, char *argv[])
-{
-  Packet p;
-  MyHeader my;
-  my.SetData (2);
-  std::cout << "send data=2" << std::endl;
-  p.AddHeader (my);
-  struct MyTag myTag;
-  myTag.m_streamId = 5;
-  p.AddTag (myTag);
-  Receive (p);
-  return 0;
-}
--- a/samples/main-query-interface.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/samples/main-query-interface.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -17,7 +17,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#include "ns3/debug.h"
+#include "ns3/log.h"
 #include "ns3/object.h"
 #include "ns3/component-manager.h"
 
@@ -79,10 +79,11 @@
 void
 AnInterface::methodA (void)
 {
+  NS_LOG_FUNCTION;
   // pre-dispatch asserts
-   NS_DEBUG_UNCOND("AnInterface pre-condition::methodA");
+  NS_LOG_LOGIC ("pre-condition");
   domethodA ();
-   NS_DEBUG_UNCOND("AnInterface post-condition::methodA\n");
+  NS_LOG_LOGIC ("post-condition");
   // post-dispatch asserts
 }
 
@@ -114,12 +115,13 @@
 void
 AnImplementation::methodImpl (void)
 {
-   NS_DEBUG_UNCOND("AnImplementation::methodImpl\n");
+  NS_LOG_FUNCTION;
 }
 
 
 AnImplementation::AnImplementation (void)
 {
+  NS_LOG_FUNCTION;
   // enable our interface
   SetInterfaceId (AnImplementation::iid);
 }
@@ -127,7 +129,7 @@
 void
 AnImplementation::domethodA () 
 {
-   NS_DEBUG_UNCOND("AnImplementation::domethodA");
+  NS_LOG_FUNCTION;
 }
 
 //
@@ -201,7 +203,7 @@
 void
 ANewImplementation::methodImpl (void)
 {
-   NS_DEBUG_UNCOND("ANewImplementation::methodImpl\n");
+  NS_LOG_FUNCTION;
 }
 
 const InterfaceId ANewImplementation::iid = 
@@ -238,7 +240,7 @@
 void
 AnExtendedImplementation::methodExtendedImpl (void)
 {
-   NS_DEBUG_UNCOND("AnExtendedImplementation::methodExtendedImpl\n");
+  NS_LOG_FUNCTION;
 }
 
 const InterfaceId AnExtendedImplementation::iid = 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/samples/main-random-topology.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,53 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+
+#include <vector>
+
+#include "ns3/ptr.h"
+#include "ns3/mobility-model.h"
+#include "ns3/mobility-model-notifier.h"
+#include "ns3/static-mobility-model.h"
+#include "ns3/random-topology.h"
+#include "ns3/default-value.h"
+#include "ns3/command-line.h"
+#include "ns3/simulator.h"
+#include "ns3/nstime.h"
+
+using namespace ns3;
+
+static void 
+CourseChange (const TraceContext &context, Ptr<const MobilityModel> position)
+{
+  Position pos = position->Get ();
+  std::cout << Simulator::Now () << ", pos=" << position << ", x=" << pos.x << ", y=" << pos.y
+            << ", z=" << pos.z << std::endl;
+}
+
+int main (int argc, char *argv[])
+{
+  DefaultValue::Bind ("RandomDiscPositionX", "100");
+  DefaultValue::Bind ("RandomDiscPositionY", "50");
+  DefaultValue::Bind ("RandomDiscPositionRho", "Uniform:0:30");
+
+  DefaultValue::Bind ("RandomTopologyPositionType", "RandomDiscPosition");
+  DefaultValue::Bind ("RandomTopologyMobilityType", "StaticMobilityModel");
+
+  CommandLine::Parse (argc, argv);
+
+  RandomTopology topology;
+
+  std::vector<Ptr<Object> > objects;
+  for (uint32_t i = 0; i < 10000; i++)
+    {
+      Ptr<MobilityModelNotifier> notifier = Create<MobilityModelNotifier> ();
+      notifier->TraceConnect ("/course-change", MakeCallback (&CourseChange));
+      objects.push_back (notifier);
+    }
+
+  topology.Layout (objects.begin (), objects.end ());
+
+  Simulator::StopAt (Seconds (100.0));
+
+  Simulator::Run ();
+  
+  return 0;
+}
--- a/samples/main-simple.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/samples/main-simple.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -4,7 +4,9 @@
 #include "ns3/simulator.h"
 #include "ns3/socket-factory.h"
 #include "ns3/socket.h"
+#include "ns3/inet-socket-address.h"
 #include "ns3/nstime.h"
+#include "ns3/packet.h"
 
 using namespace ns3;
 
@@ -12,7 +14,7 @@
 GenerateTraffic (Ptr<Socket> socket, uint32_t size)
 {
   std::cout << "at=" << Simulator::Now ().GetSeconds () << "s, tx bytes=" << size << std::endl;
-  socket->Send (0, size);
+  socket->Send (Packet (size));
   if (size > 0)
     {
       Simulator::Schedule (Seconds (0.5), &GenerateTraffic, socket, size - 50);
@@ -24,15 +26,15 @@
 }
 
 static void
-SocketPrinter (Ptr<Socket> socket, uint32_t size, const Ipv4Address &from, uint16_t fromPort)
+SocketPrinter (Ptr<Socket> socket, const Packet &packet, const Address &from)
 {
-  std::cout << "at=" << Simulator::Now ().GetSeconds () << "s, rx bytes=" << size << std::endl;
+  std::cout << "at=" << Simulator::Now ().GetSeconds () << "s, rx bytes=" << packet.GetSize () << std::endl;
 }
 
 static void
 PrintTraffic (Ptr<Socket> socket)
 {
-  socket->RecvDummy (MakeCallback (&SocketPrinter));
+  socket->SetRecvCallback (MakeCallback (&SocketPrinter));
 }
 
 void
@@ -44,10 +46,12 @@
   Ptr<SocketFactory> socketFactory = a->QueryInterface<SocketFactory> (iid);
 
   Ptr<Socket> sink = socketFactory->CreateSocket ();
-  sink->Bind (80);
+  InetSocketAddress local = InetSocketAddress (Ipv4Address::GetAny (), 80);
+  sink->Bind (local);
 
   Ptr<Socket> source = socketFactory->CreateSocket ();
-  source->Connect (Ipv4Address::GetLoopback (), 80);
+  InetSocketAddress remote = InetSocketAddress (Ipv4Address::GetLoopback (), 80);
+  source->Connect (remote);
 
   GenerateTraffic (source, 500);
   PrintTraffic (sink);
--- a/samples/main-tw.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/samples/main-tw.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -18,14 +18,14 @@
  */
 
 #include <string>
-#include "ns3/debug.h"
+#include "ns3/log.h"
 #include "ns3/trace-writer.h"
 
 using namespace ns3;
 
 int main (int argc, char *argv[])
 {
-  NS_DEBUG_UNCOND("TraceWriter Test")
+  NS_LOG_UNCOND("TraceWriter Test")
 
   TraceWriter writer1;
   writer1.Open("trace-writer-test.txt");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/samples/waf	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,1 @@
+exec "`dirname "$0"`"/../waf "$@"
--- a/samples/wscript	Thu Jul 19 13:17:35 2007 +0200
+++ b/samples/wscript	Fri Sep 28 11:59:46 2007 +0100
@@ -1,24 +1,43 @@
 ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
-import Params
 
 def build(bld):
-    def create_ns_prog(name, source, deps=['core', 'common', 'simulator']):
-        obj = bld.create_obj('cpp', 'program')
-        obj.target = name
-        obj.uselib_local = ["ns3-%s" % dep for dep in deps]
-        obj.source = source
-        return obj
-        
-    obj = create_ns_prog('main-debug', ['main-debug.cc', 'main-debug-other.cc'])
-    obj = create_ns_prog('main-callback', 'main-callback.cc')
-    obj = create_ns_prog('main-ptr', 'main-ptr.cc')
-    #obj = create_ns_prog('main-trace', 'main-trace.cc')
-    obj = create_ns_prog('main-simulator', 'main-simulator.cc')
-    obj = create_ns_prog('main-packet', 'main-packet.cc')
-    obj = create_ns_prog('main-test', 'main-test.cc')
-    obj = create_ns_prog('main-simple', 'main-simple.cc',
-                         deps=['node', 'internet-node', 'applications'])
-    #obj = create_ns_prog('main-simple-p2p', 'main-simple-p2p.cc', deps=['node', 'p2p'])
-    obj = create_ns_prog('main-default-value', 'main-default-value.cc',
-                         deps=['core', 'simulator', 'node', 'p2p'])
+    obj = bld.create_ns3_program('main-debug')
+    obj.source = ['main-debug.cc', 'main-debug-other.cc']
+
+    obj = bld.create_ns3_program('main-callback')
+    obj.source = 'main-callback.cc'
+
+    obj = bld.create_ns3_program('main-ptr')
+    obj.source = 'main-ptr.cc'
+
+    obj = bld.create_ns3_program('main-simulator')
+    obj.source = 'main-simulator.cc'
+
+    obj = bld.create_ns3_program('main-packet-header', ['common', 'simulator'])
+    obj.source = 'main-packet-header.cc'
+
+    obj = bld.create_ns3_program('main-packet-tag', ['common', 'simulator'])
+    obj.source = 'main-packet-tag.cc'
 
+    obj = bld.create_ns3_program('main-packet-printer', ['common', 'simulator', 'internet-node'])
+    obj.source = 'main-packet-printer.cc'
+
+    obj = bld.create_ns3_program('main-test')
+    obj.source = 'main-test.cc'
+
+    obj = bld.create_ns3_program('main-simple',
+                                 ['node', 'internet-node', 'onoff'])
+    obj.source = 'main-simple.cc'
+
+    obj = bld.create_ns3_program('main-default-value',
+                                 ['core', 'simulator', 'node', 'point-to-point'])
+    obj.source = 'main-default-value.cc'
+
+    obj = bld.create_ns3_program('main-grid-topology',
+                                 ['core', 'simulator', 'mobility', 'internet-node'])
+    obj.source = 'main-grid-topology.cc'
+
+    obj = bld.create_ns3_program('main-random-topology',
+                                 ['core', 'simulator', 'mobility'])
+    obj.source = 'main-random-topology.cc'
+
--- a/src/applications/onoff-application.cc	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,230 +0,0 @@
-/* -*-  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
-//
-// Author: George F. Riley<riley@ece.gatech.edu>
-//
-
-// ns3 - On/Off Data Source Application class
-// George F. Riley, Georgia Tech, Spring 2007
-// Adapted from ApplicationOnOff in GTNetS.
-
-#include "ns3/ipv4-address.h"
-#include "ns3/node.h"
-#include "ns3/nstime.h"
-#include "ns3/data-rate.h"
-#include "ns3/random-variable.h"
-#include "ns3/socket.h"
-#include "ns3/simulator.h"
-#include "ns3/socket-factory.h"
-#include "ns3/default-value.h"
-#include "onoff-application.h"
-
-using namespace std;
-
-namespace ns3 {
-
-// Defaults for rate/size
-static DataRateDefaultValue g_defaultRate ("OnOffApplicationDataRate", 
-                                           "The data rate in on state for OnOffApplication",
-                                           DataRate ("500kb/s"));
-static IntegerDefaultValue<uint32_t> g_defaultSize ("OnOffApplicationPacketSize", 
-                                                    "The size of packets sent in on state for OnOffApplication",
-                                                    512, 1);
-// Constructors
-
-OnOffApplication::OnOffApplication(Ptr<Node> n, 
-                                   const Ipv4Address  rip,
-                                   uint16_t rport,
-                                   std::string iid,
-                                   const  RandomVariable& ontime,
-                                   const  RandomVariable& offtime)
-  :  Application(n),
-     m_cbrRate (g_defaultRate.GetValue ())
-{
-  Construct (n, rip, rport, iid,
-             ontime, offtime, 
-             g_defaultSize.GetValue ());
-}
-
-OnOffApplication::OnOffApplication(Ptr<Node> n, 
-                                   const Ipv4Address  rip,
-                                   uint16_t rport,
-                                   std::string iid,
-                                   const  RandomVariable& ontime,
-                                   const  RandomVariable& offtime,
-                                   DataRate  rate,
-                                   uint32_t size)
-  :  Application(n),
-     m_cbrRate (rate)
-{
-  Construct (n, rip, rport, iid, 
-             ontime, offtime, size);
-}
-
-void
-OnOffApplication::Construct (Ptr<Node> n, 
-                             const Ipv4Address  rip,
-                             uint16_t rport,
-                             std::string iid,
-                             const  RandomVariable& onTime,
-                             const  RandomVariable& offTime,
-                             uint32_t size)
-{
-  m_socket = 0;
-  m_peerIp = rip;
-  m_peerPort = rport;
-  m_connected = false;
-  m_onTime = onTime.Copy ();
-  m_offTime = offTime.Copy ();
-  m_pktSize = size;
-  m_residualBits = 0;
-  m_lastStartTime = Seconds (0);
-  m_maxBytes = 0xffffffff;
-  m_totBytes = 0;
-  m_iid = iid;
-}
-
-
-OnOffApplication::~OnOffApplication()
-{}
-
-void 
-OnOffApplication::SetMaxBytes(uint32_t maxBytes)
-{
-  m_maxBytes = maxBytes;
-}
-
-void
-OnOffApplication::SetDefaultRate (const DataRate &rate)
-{
-  g_defaultRate.SetValue (rate);
-}
-void 
-OnOffApplication::SetDefaultSize (uint32_t size)
-{
-  g_defaultSize.SetValue (size);
-}
-
-void
-OnOffApplication::DoDispose (void)
-{
-  m_socket = 0;
-  delete m_onTime;
-  delete m_offTime;
-
-  m_onTime = 0;
-  m_offTime = 0;
-
-  // chain up
-  Application::DoDispose ();
-}
-
-
-// Application Methods
-void OnOffApplication::StartApplication()    // Called at time specified by Start
-{
-  // Create the socket if not already
-  if (!m_socket)
-    {
-      InterfaceId iid = InterfaceId::LookupByName (m_iid);
-      Ptr<SocketFactory> socketFactory = GetNode ()->QueryInterface<SocketFactory> (iid);
-      m_socket = socketFactory->CreateSocket ();
-      m_socket->Bind ();
-      m_socket->Connect (m_peerIp, m_peerPort);
-    }
-  // Insure no pending event
-  StopApplication();
-  // If we are not yet connected, there is nothing to do here
-  // The ConnectionComplete upcall will start timers at that time
-  //if (!m_connected) return;
-  ScheduleStartEvent();
-}
-
-void OnOffApplication::StopApplication()     // Called at time specified by Stop
-{
-  if (m_sendEvent.IsRunning ())
-    { // Cancel the pending send packet event
-      // Calculate residual bits since last packet sent
-      Time delta(Simulator::Now() - m_lastStartTime);
-      m_residualBits += (uint32_t)(m_cbrRate.GetBitRate() * delta.GetSeconds());
-    }
-  Simulator::Cancel(m_sendEvent);
-  Simulator::Cancel(m_startStopEvent);
-}
-
-// Event handlers
-void OnOffApplication::StartSending()
-{
-  ScheduleNextTx();  // Schedule the send packet event
-}
-
-void OnOffApplication::StopSending()
-{
-  Simulator::Cancel(m_sendEvent);
-}
-
-// Private helpers
-void OnOffApplication::ScheduleNextTx()
-{
-  if (m_totBytes < m_maxBytes)
-    {
-      uint32_t bits = m_pktSize * 8 - m_residualBits;
-      Time nextTime(Seconds (bits / 
-        static_cast<double>(m_cbrRate.GetBitRate()))); // Time till next packet
-      m_sendEvent = Simulator::Schedule(nextTime, &OnOffApplication::SendPacket, this);
-    }
-  else
-    { // All done, cancel any pending events
-      StopApplication();
-    }
-}
-
-void OnOffApplication::ScheduleStartEvent()
-{  // Schedules the event to start sending data (switch to the "On" state)
-  Time offInterval = Seconds(m_offTime->GetValue());
-  m_startStopEvent = Simulator::Schedule(offInterval, &OnOffApplication::StartSending, this);
-}
-
-void OnOffApplication::ScheduleStopEvent()
-{  // Schedules the event to stop sending data (switch to "Off" state)
-  Time onInterval = Seconds(m_onTime->GetValue());
-  Simulator::Schedule(onInterval, &OnOffApplication::StopSending, this);
-}
-
-  
-void OnOffApplication::SendPacket()
-{
-  NS_ASSERT (m_sendEvent.IsExpired ());
-  m_socket->Send(0, m_pktSize);
-  m_totBytes += m_pktSize;
-  m_lastStartTime = Simulator::Now();
-  m_residualBits = 0;
-  ScheduleNextTx();
-}
-
-void OnOffApplication::ConnectionSucceeded(Ptr<Socket>)
-{
-  m_connected = true;
-  ScheduleStartEvent();
-}
-  
-void OnOffApplication::ConnectionFailed(Ptr<Socket>)
-{
-  cout << "OnOffApplication, Connection Failed" << endl;
-}
-
-} // Namespace ns3
--- a/src/applications/onoff-application.h	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,157 +0,0 @@
-/* -*-  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
-//
-// Author: George F. Riley<riley@ece.gatech.edu>
-//
-
-// ns3 - On/Off Data Source Application class
-// George F. Riley, Georgia Tech, Spring 2007
-// Adapted from ApplicationOnOff in GTNetS.
-
-#ifndef __onoff_application_h__
-#define __onoff_application_h__
-
-#include "ns3/application.h"
-#include "ns3/event-id.h"
-#include "ns3/ptr.h"
-
-namespace ns3 {
-
-class Ipv4Address;
-class RandomVariable;
-class Socket;
-class DataRate;
-
-/**
- * \brief Generate traffic to a single destination according to an
- *        OnOff pattern.
- *
- * This traffic follows an On/Off pattern: after Application::StartApplication
- * is called, "On" and "Off" states alternate. The duration of each of
- * these states is determined with the onTime and the offTime random
- * variables. During the "Off" state, no traffic is generated.
- * During the "On" state, cbr traffic is generated. This cbr traffic is
- * characterized by the specified "data rate" and "packet size".
- */
-class OnOffApplication : public Application 
-{
-public:
-  /**
-   * \param n node associated to this application
-   * \param rip remote ip address
-   * \param rport remove port number
-   * \param iid
-   * \param ontime on time random variable
-   * \param offtime off time random variable
-   */
-  OnOffApplication(Ptr<Node> n,
-                   const Ipv4Address rip,
-                   uint16_t rport,
-                   std::string iid,
-                   const RandomVariable& ontime,
-                   const RandomVariable& offtime);
-
-  /**
-   * \param n node associated to this application
-   * \param rip remote ip address
-   * \param rport remove port number
-   * \param iid
-   * \param ontime on time random variable
-   * \param offtime off time random variable
-   * \param rate data rate when on
-   * \param size size of packets when sending data.
-   */
-  OnOffApplication(Ptr<Node> n,
-                   const Ipv4Address rip,
-                   uint16_t rport,
-                   std::string iid,
-                   const RandomVariable& ontime,
-                   const RandomVariable& offtime,
-                   DataRate  rate,
-                   uint32_t size);
-
-  virtual ~OnOffApplication();
-
-  void SetMaxBytes(uint32_t maxBytes);
-
-  /**
-   * \param r the data rate
-   *
-   * Set the data rate to use for every OnOffApplication for which
-   * the user does not specify an explicit data rate.
-   */
-  static void SetDefaultRate(const DataRate & r);
-
-  /**
-   * \param size the packet size
-   *
-   * Set the packet size to use for every OnOffApplication for
-   * which the user does not specify an explicit packet size.
-   */
-  static void SetDefaultSize (uint32_t size);
-
-protected:
-  virtual void DoDispose (void);
-private:
-  // inherited from Application base class.
-  virtual void StartApplication (void);    // Called at time specified by Start
-  virtual void StopApplication (void);     // Called at time specified by Stop
-
-  void Construct (Ptr<Node> n,
-                  const Ipv4Address rip,
-                  uint16_t rport,
-                  std::string iid,
-                  const RandomVariable& ontime,
-                  const RandomVariable& offtime,
-                  uint32_t size);
-
-
-  // Event handlers
-  void StartSending();
-  void StopSending();
-  void SendPacket();
-
-  Ptr<Socket>     m_socket;       // Associated socket
-  Ipv4Address     m_peerIp;       // Peer IP address
-  uint16_t        m_peerPort;     // Peer port
-  bool            m_connected;    // True if connected
-  RandomVariable* m_onTime;       // rng for On Time
-  RandomVariable* m_offTime;      // rng for Off Time
-  DataRate        m_cbrRate;      // Rate that data is generated
-  uint32_t        m_pktSize;      // Size of packets
-  uint32_t        m_residualBits; // Number of generated, but not sent, bits
-  Time            m_lastStartTime;// Time last packet sent
-  uint32_t        m_maxBytes;     // Limit total number of bytes sent
-  uint32_t        m_totBytes;     // Total bytes sent so far
-  EventId         m_startStopEvent;     // Event id for next start or stop event
-  EventId         m_sendEvent;    // Eventid of pending "send packet" event
-  bool            m_sending;      // True if currently in sending state
-  std::string     m_iid;
-  
-private:
-  void ScheduleNextTx();
-  void ScheduleStartEvent();
-  void ScheduleStopEvent();
-  void ConnectionSucceeded(Ptr<Socket>);
-  void ConnectionFailed(Ptr<Socket>);
-  void Ignore(Ptr<Socket>);
-};
-
-} // namespace ns3
-
-#endif
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/applications/onoff/onoff-application.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,264 @@
+/* -*-  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
+//
+// Author: George F. Riley<riley@ece.gatech.edu>
+//
+
+// ns3 - On/Off Data Source Application class
+// George F. Riley, Georgia Tech, Spring 2007
+// Adapted from ApplicationOnOff in GTNetS.
+
+#include "ns3/log.h"
+#include "ns3/address.h"
+#include "ns3/node.h"
+#include "ns3/nstime.h"
+#include "ns3/data-rate.h"
+#include "ns3/random-variable.h"
+#include "ns3/socket.h"
+#include "ns3/simulator.h"
+#include "ns3/socket-factory.h"
+#include "ns3/default-value.h"
+#include "ns3/packet.h"
+#include "onoff-application.h"
+
+NS_LOG_COMPONENT_DEFINE ("OnOffApplication");
+
+using namespace std;
+
+namespace ns3 {
+
+// Defaults for rate/size
+static DataRateDefaultValue g_defaultRate ("OnOffApplicationDataRate", 
+                                           "The data rate in on state for OnOffApplication",
+                                           DataRate ("500kb/s"));
+static NumericDefaultValue<uint32_t> g_defaultSize ("OnOffApplicationPacketSize", 
+                                                    "The size of packets sent in on state for OnOffApplication",
+                                                    512, 1);
+// Constructors
+
+OnOffApplication::OnOffApplication(Ptr<Node> n, 
+                                   const Address &remote,
+                                   std::string iid,
+                                   const  RandomVariable& ontime,
+                                   const  RandomVariable& offtime)
+  :  Application(n),
+     m_cbrRate (g_defaultRate.GetValue ())
+{
+  Construct (n, remote, iid,
+             ontime, offtime, 
+             g_defaultSize.GetValue ());
+}
+
+OnOffApplication::OnOffApplication(Ptr<Node> n, 
+                                   const Address &remote,
+                                   std::string iid,
+                                   const  RandomVariable& ontime,
+                                   const  RandomVariable& offtime,
+                                   DataRate  rate,
+                                   uint32_t size)
+  :  Application(n),
+     m_cbrRate (rate)
+{
+  NS_LOG_FUNCTION;
+  Construct (n, remote, iid, ontime, offtime, size);
+}
+
+void
+OnOffApplication::Construct (Ptr<Node> n, 
+                             const Address &remote,
+                             std::string iid,
+                             const  RandomVariable& onTime,
+                             const  RandomVariable& offTime,
+                             uint32_t size)
+{
+  NS_LOG_FUNCTION;
+
+  m_socket = 0;
+  m_peer = remote;
+  m_connected = false;
+  m_onTime = onTime.Copy ();
+  m_offTime = offTime.Copy ();
+  m_pktSize = size;
+  m_residualBits = 0;
+  m_lastStartTime = Seconds (0);
+  m_maxBytes = 0xffffffff;
+  m_totBytes = 0;
+  m_iid = iid;
+}
+
+OnOffApplication::~OnOffApplication()
+{
+  NS_LOG_FUNCTION;
+}
+
+void 
+OnOffApplication::SetMaxBytes(uint32_t maxBytes)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << maxBytes << ")");
+  m_maxBytes = maxBytes;
+}
+
+void
+OnOffApplication::SetDefaultRate (const DataRate &rate)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << &rate << ")");
+  g_defaultRate.SetValue (rate);
+}
+
+void 
+OnOffApplication::SetDefaultSize (uint32_t size)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << size << ")");
+  g_defaultSize.SetValue (size);
+}
+
+void
+OnOffApplication::DoDispose (void)
+{
+  NS_LOG_FUNCTION;
+
+  m_socket = 0;
+  delete m_onTime;
+  delete m_offTime;
+
+  m_onTime = 0;
+  m_offTime = 0;
+
+  // chain up
+  Application::DoDispose ();
+}
+
+// Application Methods
+void OnOffApplication::StartApplication() // Called at time specified by Start
+{
+  NS_LOG_FUNCTION;
+
+  // Create the socket if not already
+  if (!m_socket)
+    {
+      InterfaceId iid = InterfaceId::LookupByName (m_iid);
+      Ptr<SocketFactory> socketFactory = GetNode ()->QueryInterface<SocketFactory> (iid);
+      m_socket = socketFactory->CreateSocket ();
+      m_socket->Bind ();
+      m_socket->Connect (m_peer);
+    }
+  // Insure no pending event
+  StopApplication();
+  // If we are not yet connected, there is nothing to do here
+  // The ConnectionComplete upcall will start timers at that time
+  //if (!m_connected) return;
+  ScheduleStartEvent();
+}
+
+void OnOffApplication::StopApplication() // Called at time specified by Stop
+{
+  NS_LOG_FUNCTION;
+
+  if (m_sendEvent.IsRunning ())
+    { // Cancel the pending send packet event
+      // Calculate residual bits since last packet sent
+      Time delta(Simulator::Now() - m_lastStartTime);
+      m_residualBits += (uint32_t)(m_cbrRate.GetBitRate() * delta.GetSeconds());
+    }
+  Simulator::Cancel(m_sendEvent);
+  Simulator::Cancel(m_startStopEvent);
+}
+
+// Event handlers
+void OnOffApplication::StartSending()
+{
+  NS_LOG_FUNCTION;
+
+  ScheduleNextTx();  // Schedule the send packet event
+}
+
+void OnOffApplication::StopSending()
+{
+  NS_LOG_FUNCTION;
+
+  Simulator::Cancel(m_sendEvent);
+}
+
+// Private helpers
+void OnOffApplication::ScheduleNextTx()
+{
+  NS_LOG_FUNCTION;
+
+  if (m_totBytes < m_maxBytes)
+    {
+      uint32_t bits = m_pktSize * 8 - m_residualBits;
+      NS_LOG_LOGIC ("bits = " << bits);
+      Time nextTime(Seconds (bits / 
+        static_cast<double>(m_cbrRate.GetBitRate()))); // Time till next packet
+      NS_LOG_LOGIC ("nextTime = " << nextTime);
+      m_sendEvent = Simulator::Schedule(nextTime, 
+                                        &OnOffApplication::SendPacket, this);
+    }
+  else
+    { // All done, cancel any pending events
+      StopApplication();
+    }
+}
+
+void OnOffApplication::ScheduleStartEvent()
+{  // Schedules the event to start sending data (switch to the "On" state)
+  NS_LOG_FUNCTION;
+
+  Time offInterval = Seconds(m_offTime->GetValue());
+  NS_LOG_LOGIC ("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_LOG_FUNCTION;
+
+  Time onInterval = Seconds(m_onTime->GetValue());
+  Simulator::Schedule(onInterval, &OnOffApplication::StopSending, this);
+}
+
+  
+void OnOffApplication::SendPacket()
+{
+  NS_LOG_FUNCTION;
+
+  NS_ASSERT (m_sendEvent.IsExpired ());
+  m_socket->Send(Packet (m_pktSize));
+  m_totBytes += m_pktSize;
+  m_lastStartTime = Simulator::Now();
+  m_residualBits = 0;
+  ScheduleNextTx();
+}
+
+void OnOffApplication::ConnectionSucceeded(Ptr<Socket>)
+{
+  NS_LOG_FUNCTION;
+
+  m_connected = true;
+  ScheduleStartEvent();
+}
+  
+void OnOffApplication::ConnectionFailed(Ptr<Socket>)
+{
+  NS_LOG_FUNCTION;
+  cout << "OnOffApplication, Connection Failed" << endl;
+}
+
+} // Namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/applications/onoff/onoff-application.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,151 @@
+/* -*-  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
+//
+// Author: George F. Riley<riley@ece.gatech.edu>
+//
+
+// ns3 - On/Off Data Source Application class
+// George F. Riley, Georgia Tech, Spring 2007
+// Adapted from ApplicationOnOff in GTNetS.
+
+#ifndef __onoff_application_h__
+#define __onoff_application_h__
+
+#include "ns3/application.h"
+#include "ns3/event-id.h"
+#include "ns3/ptr.h"
+#include "ns3/data-rate.h"
+
+namespace ns3 {
+
+class Address;
+class RandomVariable;
+class Socket;
+
+/**
+ * \brief Generate traffic to a single destination according to an
+ *        OnOff pattern.
+ *
+ * This traffic follows an On/Off pattern: after Application::StartApplication
+ * is called, "On" and "Off" states alternate. The duration of each of
+ * these states is determined with the onTime and the offTime random
+ * variables. During the "Off" state, no traffic is generated.
+ * During the "On" state, cbr traffic is generated. This cbr traffic is
+ * characterized by the specified "data rate" and "packet size".
+ */
+class OnOffApplication : public Application 
+{
+public:
+  /**
+   * \param n node associated to this application
+   * \param remote remote ip address
+   * \param iid
+   * \param ontime on time random variable
+   * \param offtime off time random variable
+   */
+  OnOffApplication(Ptr<Node> n,
+                   const Address &remote,
+                   std::string iid,
+                   const RandomVariable& ontime,
+                   const RandomVariable& offtime);
+
+  /**
+   * \param n node associated to this application
+   * \param remote remote ip address
+   * \param iid
+   * \param ontime on time random variable
+   * \param offtime off time random variable
+   * \param rate data rate when on
+   * \param size size of packets when sending data.
+   */
+  OnOffApplication(Ptr<Node> n,
+                   const Address &remote,
+                   std::string iid,
+                   const RandomVariable& ontime,
+                   const RandomVariable& offtime,
+                   DataRate  rate,
+                   uint32_t size);
+
+  virtual ~OnOffApplication();
+
+  void SetMaxBytes(uint32_t maxBytes);
+
+  /**
+   * \param r the data rate
+   *
+   * Set the data rate to use for every OnOffApplication for which
+   * the user does not specify an explicit data rate.
+   */
+  static void SetDefaultRate(const DataRate & r);
+
+  /**
+   * \param size the packet size
+   *
+   * Set the packet size to use for every OnOffApplication for
+   * which the user does not specify an explicit packet size.
+   */
+  static void SetDefaultSize (uint32_t size);
+
+protected:
+  virtual void DoDispose (void);
+private:
+  // inherited from Application base class.
+  virtual void StartApplication (void);    // Called at time specified by Start
+  virtual void StopApplication (void);     // Called at time specified by Stop
+
+  void Construct (Ptr<Node> n,
+                  const Address &remote,
+                  std::string iid,
+                  const RandomVariable& ontime,
+                  const RandomVariable& offtime,
+                  uint32_t size);
+
+
+  // Event handlers
+  void StartSending();
+  void StopSending();
+  void SendPacket();
+
+  Ptr<Socket>     m_socket;       // Associated socket
+  Address         m_peer;         // Peer address
+  bool            m_connected;    // True if connected
+  RandomVariable* m_onTime;       // rng for On Time
+  RandomVariable* m_offTime;      // rng for Off Time
+  DataRate        m_cbrRate;      // Rate that data is generated
+  uint32_t        m_pktSize;      // Size of packets
+  uint32_t        m_residualBits; // Number of generated, but not sent, bits
+  Time            m_lastStartTime;// Time last packet sent
+  uint32_t        m_maxBytes;     // Limit total number of bytes sent
+  uint32_t        m_totBytes;     // Total bytes sent so far
+  EventId         m_startStopEvent;     // Event id for next start or stop event
+  EventId         m_sendEvent;    // Eventid of pending "send packet" event
+  bool            m_sending;      // True if currently in sending state
+  std::string     m_iid;
+  
+private:
+  void ScheduleNextTx();
+  void ScheduleStartEvent();
+  void ScheduleStopEvent();
+  void ConnectionSucceeded(Ptr<Socket>);
+  void ConnectionFailed(Ptr<Socket>);
+  void Ignore(Ptr<Socket>);
+};
+
+} // namespace ns3
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/applications/onoff/waf	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,1 @@
+exec "`dirname "$0"`"/../../../waf "$@"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/applications/onoff/wscript	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,12 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def build(bld):
+    module = bld.create_ns3_module('onoff', ['core'])
+    module.source = [
+        'onoff-application.cc',
+        ]
+    headers = bld.create_obj('ns3header')
+    headers.source = [
+        'onoff-application.h',
+        ]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/applications/packet-sink/packet-sink.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,109 @@
+/* -*- 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/log.h"
+#include "ns3/inet-socket-address.h"
+#include "ns3/node.h"
+#include "ns3/socket.h"
+#include "ns3/simulator.h"
+#include "ns3/socket-factory.h"
+#include "ns3/packet.h"
+#include "packet-sink.h"
+
+using namespace std;
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE ("PacketSinkApplication");
+
+// Constructors
+
+PacketSink::PacketSink (Ptr<Node> n, 
+                        const Address &local,
+                        std::string iid)
+  :  Application(n)
+{
+  Construct (n, local, iid);
+}
+
+void
+PacketSink::Construct (Ptr<Node> n, 
+                       const Address &local,
+                       std::string iid)
+{
+  m_socket = 0;
+  m_local = local;
+  m_iid = iid;
+}
+
+PacketSink::~PacketSink()
+{}
+
+void
+PacketSink::DoDispose (void)
+{
+  m_socket = 0;
+
+  // chain up
+  Application::DoDispose ();
+}
+
+
+// Application Methods
+void PacketSink::StartApplication()    // Called at time specified by Start
+{
+  // Create the socket if not already
+  if (!m_socket)
+    {
+      InterfaceId iid = InterfaceId::LookupByName (m_iid);
+      Ptr<SocketFactory> socketFactory = 
+        GetNode ()->QueryInterface<SocketFactory> (iid);
+      m_socket = socketFactory->CreateSocket ();
+      m_socket->Bind (m_local);
+    }
+  m_socket->SetRecvCallback((Callback<void, Ptr<Socket>, const Packet &,
+    const Address &>) MakeCallback(&PacketSink::Receive, this));
+}
+
+void PacketSink::StopApplication()     // Called at time specified by Stop
+{
+  if (!m_socket) 
+    {
+      m_socket->SetRecvCallback((Callback<void, Ptr<Socket>, const Packet &,
+                               const Address &>) NULL);
+ 
+    }
+}
+
+// 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 (InetSocketAddress::IsMatchingType (from))
+    {
+      InetSocketAddress address = InetSocketAddress::ConvertFrom (from);
+      NS_LOG_INFO ("Received " << packet.GetSize() << " bytes from " << 
+        address.GetIpv4() << " [" << address << "]---'" << 
+        packet.PeekData() << "'");
+      // TODO:  Add a tracing source here
+    }
+}
+
+} // Namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/applications/packet-sink/packet-sink.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,87 @@
+/* -*- 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__
+
+#include "ns3/application.h"
+#include "ns3/event-id.h"
+#include "ns3/ptr.h"
+
+namespace ns3 {
+
+class Address;
+class Socket;
+class Packet;
+
+/**
+ * \brief Receive and consume traffic generated to an IP address and port
+ *
+ * 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 address to bind to
+   * \param iid string to identify transport protocol of interest
+   */
+  PacketSink (Ptr<Node> n,
+              const Address &local,
+              std::string iid);
+
+  virtual ~PacketSink ();
+
+protected:
+  virtual void DoDispose (void);
+private:
+  // inherited from Application base class.
+  virtual void StartApplication (void);    // Called at time specified by Start
+  virtual void StopApplication (void);     // Called at time specified by Stop
+
+  void Construct (Ptr<Node> n,
+                  const Address &local,
+                  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")
+  
+};
+
+} // namespace ns3
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/applications/packet-sink/waf	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,1 @@
+exec "`dirname "$0"`"/../../../waf "$@"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/applications/packet-sink/wscript	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,12 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def build(bld):
+    module = bld.create_ns3_module('packet-sink', ['node'])
+    module.source = [
+        'packet-sink.cc',
+        ]
+    headers = bld.create_obj('ns3header')
+    headers.source = [
+        'packet-sink.h',
+        ]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/applications/udp-echo/udp-echo-client.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,168 @@
+/* -*- 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
+ */
+#include "ns3/log.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/nstime.h"
+#include "ns3/inet-socket-address.h"
+#include "ns3/socket.h"
+#include "ns3/simulator.h"
+#include "ns3/socket-factory.h"
+#include "ns3/packet.h"
+#include "udp-echo-client.h"
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE ("UdpEchoClientApplication");
+
+UdpEchoClient::UdpEchoClient (
+  Ptr<Node> n,
+  Ipv4Address serverAddress,
+  uint16_t serverPort,
+  uint32_t count,
+  Time interval,
+  uint32_t size)
+: 
+  Application(n)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << n << ", " << serverAddress <<
+    ", " << serverPort << ", " << count << ", " << interval <<
+    ", " << size << ")");
+
+  Construct (n, serverAddress, serverPort, count, interval, size);
+}
+
+UdpEchoClient::~UdpEchoClient()
+{
+  NS_LOG_FUNCTION;
+}
+
+void
+UdpEchoClient::Construct (
+  Ptr<Node> n,
+  Ipv4Address serverAddress,
+  uint16_t serverPort,
+  uint32_t count,
+  Time interval,
+  uint32_t size)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << n << ", " << serverAddress <<
+    ", " << serverPort << ", " << count << ", " << interval <<
+    ", " << size << ")");
+
+  m_node = n;
+  m_serverAddress = serverAddress;
+  m_serverPort = serverPort;
+  m_count = count;
+  m_interval = interval;
+  m_size = size;
+
+  m_sent = 0;
+  m_socket = 0;
+  m_peer = InetSocketAddress (serverAddress, serverPort);
+  m_sendEvent = EventId ();
+}
+
+void
+UdpEchoClient::DoDispose (void)
+{
+  NS_LOG_FUNCTION;
+  Application::DoDispose ();
+}
+
+void 
+UdpEchoClient::StartApplication (void)
+{
+  NS_LOG_FUNCTION;
+
+  if (!m_socket)
+    {
+      InterfaceId iid = InterfaceId::LookupByName ("Udp");
+      Ptr<SocketFactory> socketFactory = 
+        GetNode ()->QueryInterface<SocketFactory> (iid);
+      m_socket = socketFactory->CreateSocket ();
+      m_socket->Bind ();
+      m_socket->Connect (m_peer);
+    }
+
+  m_socket->SetRecvCallback((Callback<void, Ptr<Socket>, const Packet &,
+    const Address &>) MakeCallback(&UdpEchoClient::Receive, this));
+
+  ScheduleTransmit (Seconds(0.));
+}
+
+void 
+UdpEchoClient::StopApplication ()
+{
+  NS_LOG_FUNCTION;
+
+  if (!m_socket) 
+    {
+      m_socket->SetRecvCallback((Callback<void, Ptr<Socket>, const Packet &,
+        const Address &>) NULL);
+    }
+
+  Simulator::Cancel(m_sendEvent);
+}
+
+void 
+UdpEchoClient::ScheduleTransmit (Time dt)
+{
+  NS_LOG_FUNCTION;
+  m_sendEvent = Simulator::Schedule(dt, &UdpEchoClient::Send, this);
+}
+
+void 
+UdpEchoClient::Send (void)
+{
+  NS_LOG_FUNCTION;
+
+  NS_ASSERT (m_sendEvent.IsExpired ());
+
+  Packet p (m_size);
+  m_socket->Send (p);
+  ++m_sent;
+
+  NS_LOG_INFO ("Sent " << m_size << " bytes to " << m_serverAddress);
+
+  if (m_sent < m_count) 
+    {
+      ScheduleTransmit (m_interval);
+    }
+}
+
+void
+UdpEchoClient::Receive(
+  Ptr<Socket> socket, 
+  const Packet &packet,
+  const Address &from) 
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << socket << ", " << packet << ", " << from << ")");
+
+  if (InetSocketAddress::IsMatchingType (from))
+    {
+      InetSocketAddress address = InetSocketAddress::ConvertFrom (from);
+      NS_LOG_INFO ("Received " << packet.GetSize() << " bytes from " << 
+        address.GetIpv4());
+    }
+}
+
+
+} // Namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/applications/udp-echo/udp-echo-client.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,72 @@
+/* -*- 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
+ */
+
+#ifndef __UDP_ECHO_CLIENT_H__
+#define __UDP_ECHO_CLIENT_H__
+
+#include "ns3/application.h"
+#include "ns3/event-id.h"
+#include "ns3/ptr.h"
+
+namespace ns3 {
+
+class Address;
+class Socket;
+class Packet;
+
+class UdpEchoClient : public Application 
+{
+public:
+  UdpEchoClient (Ptr<Node> n, Ipv4Address serverAddr, uint16_t serverPort,
+    uint32_t count, Time interval, uint32_t size);
+
+  virtual ~UdpEchoClient ();
+
+protected:
+  virtual void DoDispose (void);
+
+private:
+  void Construct (Ptr<Node> n, Ipv4Address serverAddr, uint16_t serverPort,
+    uint32_t count, Time interval, uint32_t size);
+
+  virtual void StartApplication (void);
+  virtual void StopApplication (void);
+
+  void ScheduleTransmit (Time dt);
+  void Send (void);
+
+  void Receive(Ptr<Socket> socket, const Packet &packet, const Address &from);
+
+  Ptr<Node> m_node;
+  Ipv4Address m_serverAddress;
+  uint16_t m_serverPort;
+  uint32_t m_count;
+  Time m_interval;
+  uint32_t m_size;
+
+  uint32_t m_sent;
+  Ptr<Socket> m_socket;
+  Address m_peer;
+  EventId m_sendEvent;
+
+};
+
+} // namespace ns3
+
+#endif // __UDP_ECHO_CLIENT_H__
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/applications/udp-echo/udp-echo-server.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,123 @@
+/* -*- 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
+ */
+
+#include "ns3/log.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/nstime.h"
+#include "ns3/inet-socket-address.h"
+#include "ns3/socket.h"
+#include "ns3/simulator.h"
+#include "ns3/socket-factory.h"
+#include "ns3/packet.h"
+
+#include "udp-echo-server.h"
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE ("UdpEchoServerApplication");
+
+UdpEchoServer::UdpEchoServer (
+  Ptr<Node> n,
+  uint16_t port)
+: 
+  Application(n)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << n << ", " << port << ")");
+
+  Construct (n, port);
+}
+
+UdpEchoServer::~UdpEchoServer()
+{
+  NS_LOG_FUNCTION;
+}
+
+void
+UdpEchoServer::Construct (
+  Ptr<Node> n,
+  uint16_t port)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << n << ", " << port << ")");
+
+  m_node = n;
+  m_port = port;
+
+  m_socket = 0;
+  m_local = InetSocketAddress (Ipv4Address::GetAny (), port);
+}
+
+void
+UdpEchoServer::DoDispose (void)
+{
+  NS_LOG_FUNCTION;
+  Application::DoDispose ();
+}
+
+void 
+UdpEchoServer::StartApplication (void)
+{
+  NS_LOG_FUNCTION;
+
+  if (!m_socket)
+    {
+      InterfaceId iid = InterfaceId::LookupByName ("Udp");
+      Ptr<SocketFactory> socketFactory = 
+        GetNode ()->QueryInterface<SocketFactory> (iid);
+      m_socket = socketFactory->CreateSocket ();
+      m_socket->Bind (m_local);
+    }
+
+  m_socket->SetRecvCallback((Callback<void, Ptr<Socket>, const Packet &,
+    const Address &>) MakeCallback(&UdpEchoServer::Receive, this));
+}
+
+void 
+UdpEchoServer::StopApplication ()
+{
+  NS_LOG_FUNCTION;
+
+  if (!m_socket) 
+    {
+      m_socket->SetRecvCallback((Callback<void, Ptr<Socket>, const Packet &,
+        const Address &>) NULL);
+    }
+}
+
+void
+UdpEchoServer::Receive(
+  Ptr<Socket> socket, 
+  const Packet &packet,
+  const Address &from) 
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << socket << ", " << packet << ", " << from << ")");
+
+  if (InetSocketAddress::IsMatchingType (from))
+    {
+      InetSocketAddress address = InetSocketAddress::ConvertFrom (from);
+      NS_LOG_INFO ("Received " << packet.GetSize() << " bytes from " << 
+        address.GetIpv4());
+
+      NS_LOG_LOGIC ("Echoing packet");
+      socket->SendTo (from, packet);
+    }
+}
+
+} // Namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/applications/udp-echo/udp-echo-server.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,59 @@
+/* -*- 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
+ */
+
+#ifndef __UDP_ECHO_SERVER_H__
+#define __UDP_ECHO_SERVER_H__
+
+#include "ns3/application.h"
+#include "ns3/event-id.h"
+#include "ns3/ptr.h"
+
+namespace ns3 {
+
+class Address;
+class Socket;
+class Packet;
+
+class UdpEchoServer : public Application 
+{
+public:
+  UdpEchoServer (Ptr<Node> n, uint16_t clientPort);
+  virtual ~UdpEchoServer ();
+
+protected:
+  virtual void DoDispose (void);
+
+private:
+  void Construct (Ptr<Node> n, uint16_t clientPort);
+
+  virtual void StartApplication (void);
+  virtual void StopApplication (void);
+
+  void Receive(Ptr<Socket> socket, const Packet &packet, const Address &from);
+
+  Ptr<Node> m_node;
+  uint16_t m_port;
+
+  Ptr<Socket> m_socket;
+  Address m_local;
+};
+
+} // namespace ns3
+
+#endif // __UDP_ECHO_SERVER_H__
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/applications/udp-echo/waf	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,1 @@
+exec "`dirname "$0"`"/../../../waf "$@"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/applications/udp-echo/wscript	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,14 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def build(bld):
+    module = bld.create_ns3_module('udp-echo', ['internet-node'])
+    module.source = [
+        'udp-echo-client.cc',
+        'udp-echo-server.cc',
+        ]
+    headers = bld.create_obj('ns3header')
+    headers.source = [
+        'udp-echo-client.h',
+        'udp-echo-server.h',
+        ]
+
--- a/src/applications/wscript	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,20 +0,0 @@
-## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
-
-
-def configure(conf):
-    conf.env.append_value('NS3_MODULES', 'ns3-applications')
-
-
-def build(bld):
-    obj = bld.create_obj('cpp', 'shlib')
-    obj.name = 'ns3-applications'
-    obj.target = obj.name
-    obj.uselib_local = ['ns3-node']
-    obj.source = [
-        'onoff-application.cc',
-        ]
-
-    headers = bld.create_obj('ns3header')
-    headers.source = [
-        'onoff-application.h',
-        ]
--- a/src/common/array-trace-resolver.h	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,137 +0,0 @@
-/* -*- 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
- * 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 ARRAY_TRACE_RESOLVER_H
-#define ARRAY_TRACE_RESOLVER_H
-
-#include <stdint.h>
-#include <string>
-#include "ns3/callback.h"
-#include "trace-resolver.h"
-
-namespace ns3 {
-
-/**
- * \brief a helper class to offer trace resolution for an array of objects.
- * \ingroup lowleveltracing
- */
-template <typename T>
-class ArrayTraceResolver : public TraceResolver
-{
-public:
-  /**
-   * \brief array index trace context
-   *
-   * During namespace parsing, ns3::ArrayTraceResolver will
-   * embed an instance of this class in the TraceContext 
-   * associated to every child object of the object stored
-   * at the index.
-   *
-   * The reason why this class exists is to ensure that we 
-   * need to ensure that we can store a unique type as context 
-   * into the TraceContext associated to this trace resolver.
-   */
-  class Index
-  {
-  public:
-    Index ();
-    Index (uint32_t index);
-    /**
-     * The Index is automatically convertible to the 
-     * uin32_t type such that it really behaves like a uint32_t
-     * array index for the user. 
-     *
-     * \returns the index itself
-     */
-    operator uint32_t ();
-  private:
-    uint32_t m_index;
-  };
-  /**
-   * \param context trace context associated to this trace resolver
-   * \param getSize callback which returns dynamically the size of underlying array
-   * \param get callback which returns any element in the underlying array
-   *
-   * Construct a trace resolver which can match any input integer
-   * against an element in an array. The array is accessed using a 
-   * pair of callbacks. It is the responsability of the user to
-   * provide two such callbacks whose job is to adapt the array
-   * API to the resolver needs. Each element of the array is expected
-   * to provide a method named CreateTraceResolver which takes as
-   * only argument a reference to a const TraceContext and returns
-   * a pointer to a TraceResolver. i.e. the signature is:
-   * TraceResolver * (*) (TraceContext const &)
-   */
-  ArrayTraceResolver (TraceContext const &context,
-                      Callback<uint32_t> getSize, 
-                      Callback<T *, uint32_t> get);
-private:
-  virtual TraceResolverList DoLookup (std::string id) const;
-  Callback<uint32_t> m_getSize;
-  Callback<T *, uint32_t> m_get;
-};
-}//namespace ns3
-
-namespace ns3 {
-
-template <typename T>
-ArrayTraceResolver<T>::Index::Index ()
-  : m_index ()
-{}
-template <typename T>
-ArrayTraceResolver<T>::Index::Index (uint32_t index)
-  : m_index (index)
-{}
-template <typename T>
-ArrayTraceResolver<T>::Index::operator uint32_t ()
-{
-  return m_index;
-}
-
-template <typename T>
-ArrayTraceResolver<T>::ArrayTraceResolver (TraceContext const &context,
-                                           Callback<uint32_t> getSize, 
-                                           Callback<T *, uint32_t> get)
-  : TraceResolver (context),
-    m_getSize (getSize),
-    m_get (get)
-{}
-template <typename T>
-TraceResolver::TraceResolverList 
-ArrayTraceResolver<T>::DoLookup (std::string id) const
-{
-  TraceResolverList list;
-  if (id == "*")
-  {
-    for (uint32_t i = 0; i < m_getSize (); i++)
-    {
-	  TraceContext context = GetContext ();
-      typename ArrayTraceResolver<T>::Index index = typename ArrayTraceResolver<T>::Index (i);
-	  context.Add (index);
-	  list.push_back (m_get (i)->CreateTraceResolver (context));
-    }
-  }
-  return list;
-}
-
-
-}//namespace ns3
-
-#endif /* ARRAY_TRACE_RESOLVER_H */
--- a/src/common/buffer.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/common/buffer.cc	Fri Sep 28 11:59:46 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,376 +19,534 @@
  */
 #include "buffer.h"
 #include "ns3/assert.h"
-
+#include "ns3/log.h"
 #include <iostream>
-//#define TRACE(x) std::cout << x << std::endl;
-#define TRACE(x)
+
+NS_LOG_COMPONENT_DEFINE ("Buffer");
+
+#define LOG_INTERNAL_STATE(y)                                                                    \
+NS_LOG_LOGIC (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 ();
+};
+
+static struct BufferData *BufferAllocate (uint32_t reqSize);
 
-struct Buffer::BufferData *
-Buffer::Allocate (uint32_t reqSize, uint32_t reqStart)
+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++)
+    {
+      BufferDeallocate (*i);
+    }
+}
+
+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;
+  LOG_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;
+      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;
+  LOG_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));
+  LOG_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));
+  LOG_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) 
     {
@@ -398,50 +555,442 @@
   Buffer tmp = *this;
   tmp.RemoveAtStart (start);
   tmp.RemoveAtEnd (GetSize () - (start + length));
+  NS_ASSERT (CheckInternalState ());
   return tmp;
 }
 
+Buffer 
+Buffer::CreateFullCopy (void) const
+{
+  NS_ASSERT (CheckInternalState ());
+  if (m_zeroAreaEnd != 0) 
+    {
+      Buffer tmp;
+      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_end - m_zeroAreaEnd;
+      tmp.AddAtEnd (dataEnd);
+      Buffer::Iterator i = tmp.End ();
+      i.Prev (dataEnd);
+      i.Write (m_data->m_data+m_zeroAreaStart,dataEnd);
+      return tmp;
+    }
+  NS_ASSERT (CheckInternalState ());
+  return *this;
+}
+
 void
 Buffer::TransformIntoRealBuffer (void) const
 {
-  if (m_zeroAreaSize != 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 (dataStart);
-      tmp.Begin ().Write (m_data->m_data+m_start, dataStart);
-      uint32_t dataEnd = m_size - (m_data->m_initialStart - m_start);
-      tmp.AddAtEnd (dataEnd);
-      Buffer::Iterator i = tmp.End ();
-      i.Prev (dataEnd);
-      i.Write (m_data->m_data+m_data->m_initialStart,dataEnd);
-      *const_cast<Buffer *> (this) = tmp;
-    }
+  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
 
 #include "ns3/test.h"
+#include "ns3/random-variable.h"
 #include <iomanip>
 
+
 namespace ns3 {
 
 class BufferTest: public Test {
@@ -501,14 +1050,14 @@
   uint8_t bytes[] = {__VA_ARGS__};             \
   if (!EnsureWrittenBytes (buffer, n , bytes)) \
     {                                          \
-      ok = false;                              \
+      result = false;                          \
     }                                          \
   }
 
 bool
 BufferTest::RunTests (void)
 {
-  bool ok = true;
+  bool result = true;
   Buffer buffer;
   Buffer::Iterator i;
   buffer.AddAtStart (6);
@@ -555,7 +1104,7 @@
   i.Prev (2);
   if (i.ReadNtohU16 () != 0xff00) 
     {
-      ok = false;
+      result = false;
     }
   i.Prev (2);
   i.WriteU16 (saved);
@@ -645,7 +1194,7 @@
   buffer.RemoveAtEnd (8);
   if (buffer.GetSize () != 0) 
     {
-      ok = false;
+      result = false;
     }
 
   buffer = Buffer (6);
@@ -663,14 +1212,51 @@
   i.Prev (4);
   i.WriteU8 (1, 4);
 
-  return ok;
+  buffer = Buffer (1);
+  buffer.AddAtEnd (100);
+  i = buffer.End ();
+  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;
+    const uint32_t chunkSize = 67624;
+    UniformVariable bytesRng (0, 256);
+
+    Buffer inputBuffer;
+    Buffer outputBuffer;
+    
+    inputBuffer.AddAtEnd (actualSize);
+    {
+      Buffer::Iterator iter = inputBuffer.Begin ();
+      for (uint32_t i = 0; i < actualSize; i++)
+        iter.WriteU8 (static_cast<uint8_t> (bytesRng.GetValue ()));
+    }
+
+    outputBuffer.AddAtEnd (chunkSize);
+    Buffer::Iterator iter = outputBuffer.End ();
+    iter.Prev (chunkSize);
+    iter.Write (inputBuffer.PeekData (), chunkSize);
+
+    NS_TEST_ASSERT (memcmp (inputBuffer.PeekData (), outputBuffer.PeekData (), chunkSize) == 0);
+  }
+
+  return result;
 }
 
 
 
 static BufferTest gBufferTest;
 
-}; // namespace ns3
+} // namespace ns3
 
 #endif /* RUN_SELF_TESTS */
 
--- a/src/common/buffer.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/common/buffer.h	Fri Sep 28 11:59:46 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 int32_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, uint16_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,393 +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];
-  };
-  typedef std::vector<struct Buffer::BufferData*> BufferDataList;
 
-  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);
+  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);
 
-  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)
+void
+Buffer::Iterator::WriteU8 (uint8_t data)
 {
-  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
-{
-  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;
-}
-int32_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;
-  return end - start;
-}
-
-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) 
+  if (m_current < m_zeroStart)
     {
-      index = m_current;
-    } 
-  else 
-    {
-      index = m_current - (m_zeroEnd-m_zeroStart);
+      m_data[m_current] = data;
+      m_current++;
     }
-  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 (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;
+  else
+    {
+      m_data[m_current - (m_zeroEnd-m_zeroStart)] = data;
+      m_current++;      
+    }
 }
 
 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, uint16_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/callback-trace-source.cc	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,95 +0,0 @@
-/* -*- 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
- * 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 "callback-trace-source.h"
-#include "ns3/test.h"
-
-namespace ns3 {
-
-class CallbackTraceSourceTest : public Test 
-{
-public:
-  CallbackTraceSourceTest ();
-  virtual ~CallbackTraceSourceTest ();
-  virtual bool RunTests (void);
-private:
-  void CbOne (TraceContext const &context, uint8_t a, double b);
-  void CbTwo (TraceContext const &context, uint8_t a, double b);
-
-  bool m_one;
-  bool m_two;
-};
-
-CallbackTraceSourceTest::CallbackTraceSourceTest ()
-  : Test ("CallbackTraceSource")
-{}
-CallbackTraceSourceTest::~CallbackTraceSourceTest ()
-{}
-void
-CallbackTraceSourceTest::CbOne (TraceContext const &context, uint8_t a, double b)
-{
-  m_one = true;
-}
-void
-CallbackTraceSourceTest::CbTwo (TraceContext const &context, uint8_t a, double b)
-{
-  m_two = true;
-}
-bool 
-CallbackTraceSourceTest::RunTests (void)
-{
-  bool ok = true;
-  TraceContext ctx;
-
-  CallbackTraceSource<uint8_t,double> trace;
-  trace.AddCallback (MakeCallback (&CallbackTraceSourceTest::CbOne, this), ctx);
-  trace.AddCallback (MakeCallback (&CallbackTraceSourceTest::CbTwo, this), ctx);
-  m_one = false;
-  m_two = false;
-  trace (1, 2);
-  if (!m_one || !m_two)
-    {
-      ok = false;
-    }
-  trace.RemoveCallback (MakeCallback (&CallbackTraceSourceTest::CbOne, this));
-  m_one = false;
-  m_two = false;
-  trace (1, 2);
-  if (m_one || !m_two)
-    {
-      ok = false;
-    }
-  trace.RemoveCallback (MakeCallback (&CallbackTraceSourceTest::CbTwo, this));
-  m_one = false;
-  m_two = false;
-  trace (1, 2);
-  if (m_one || m_two)
-    {
-      ok = false;
-    }
-
-  return ok;
-}
-
-CallbackTraceSourceTest g_callbackTraceTest;
-
-
-
-}//namespace ns3
--- a/src/common/callback-trace-source.h	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,157 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2005,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
- * 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 CALLBACK_TRACE_H
-#define CALLBACK_TRACE_H
-
-#include <list>
-#include "ns3/callback.h"
-#include "ns3/fatal-error.h"
-#include "trace-context.h"
-
-namespace ns3 {
-
-
-/**
- * \brief log arbitrary number of parameters to a matching ns3::Callback
- * \ingroup lowleveltracing
- *
- * Whenever operator () is invoked on this class, the call and its arguments
- * are forwarded to the internal matching ns3::Callback.
- */
-template<typename T1 = empty, typename T2 = empty, 
-         typename T3 = empty, typename T4 = empty>
-class CallbackTraceSource {
-public:
-  CallbackTraceSource ();
-  void AddCallback (CallbackBase const & callback, TraceContext const & context);
-  void RemoveCallback (CallbackBase const & callback);
-  void operator() (void);
-  void operator() (T1 a1);
-  void operator() (T1 a1, T2 a2);
-  void operator() (T1 a1, T2 a2, T3 a3);
-  void operator() (T1 a1, T2 a2, T3 a3, T4 a4);
-
-private:
-  typedef std::list<Callback<void,TraceContext const &,T1,T2,T3,T4> > CallbackList;
-  TraceContext m_context;
-  CallbackList m_callbackList;
-};
-
-}; // namespace ns3
-
-// implementation below.
-
-namespace ns3 {
-
-template<typename T1, typename T2, 
-         typename T3, typename T4>
-CallbackTraceSource<T1,T2,T3,T4>::CallbackTraceSource ()
-  : m_callbackList () 
-{}
-template<typename T1, typename T2, 
-         typename T3, typename T4>
-void 
-CallbackTraceSource<T1,T2,T3,T4>::AddCallback (CallbackBase const & callback,
-                                               TraceContext const &context)
-{
-  Callback<void,TraceContext const &,T1,T2,T3,T4> cb;
-  cb.Assign (callback);
-  m_context.Add (context);
-  m_callbackList.push_back (cb);
-}
-template<typename T1, typename T2, 
-         typename T3, typename T4>
-void 
-CallbackTraceSource<T1,T2,T3,T4>::RemoveCallback (CallbackBase const & callback)
-{
-  for (typename CallbackList::iterator i = m_callbackList.begin ();
-       i != m_callbackList.end (); /* empty */)
-    {
-      if ((*i).IsEqual (callback))
-	{
-	  i = m_callbackList.erase (i);
-	}
-      else
-	{
-	  i++;
-	}
-    }
-}
-template<typename T1, typename T2, 
-         typename T3, typename T4>
-void 
-CallbackTraceSource<T1,T2,T3,T4>::operator() (void) 
-{
-  for (typename CallbackList::iterator i = m_callbackList.begin ();
-       i != m_callbackList.end (); i++)
-    {
-      (*i) (m_context);
-    }
-}
-template<typename T1, typename T2, 
-         typename T3, typename T4>
-void 
-CallbackTraceSource<T1,T2,T3,T4>::operator() (T1 a1) 
-{
-  for (typename CallbackList::iterator i = m_callbackList.begin ();
-       i != m_callbackList.end (); i++)
-    {
-      (*i) (m_context, a1);
-    }
-}
-template<typename T1, typename T2, 
-         typename T3, typename T4>
-void 
-CallbackTraceSource<T1,T2,T3,T4>::operator() (T1 a1, T2 a2) 
-{
-  for (typename CallbackList::iterator i = m_callbackList.begin ();
-       i != m_callbackList.end (); i++)
-    {
-      (*i) (m_context, a1, a2);
-    }
-}
-template<typename T1, typename T2, 
-         typename T3, typename T4>
-void 
-CallbackTraceSource<T1,T2,T3,T4>::operator() (T1 a1, T2 a2, T3 a3) 
-{
-  for (typename CallbackList::iterator i = m_callbackList.begin ();
-       i != m_callbackList.end (); i++)
-    {
-      (*i) (m_context, a1, a2, a3);
-    }
-}
-template<typename T1, typename T2, 
-         typename T3, typename T4>
-void 
-CallbackTraceSource<T1,T2,T3,T4>::operator() (T1 a1, T2 a2, T3 a3, T4 a4) 
-{
-  for (typename CallbackList::iterator i = m_callbackList.begin ();
-       i != m_callbackList.end (); i++)
-    {
-      (*i) (m_context, a1, a2, a3, a4);
-    }
-}
-
-}//namespace ns3
-
-#endif /* CALLBACK_TRACE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/chunk-registry.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,117 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2005 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
+ * 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 "chunk-registry.h"
+#include "ns3/assert.h"
+
+namespace ns3 {
+
+ChunkRegistry::InfoVector *
+ChunkRegistry::GetInfoVector (void)
+{
+  static InfoVector vec;
+  return &vec;
+}
+
+std::string 
+ChunkRegistry::GetUidStringFromUid (uint32_t uid)
+{
+  InfoVector *vec = GetInfoVector ();
+  NS_ASSERT (uid >= 1 && uid <= vec->size ());
+  Info info = (*vec)[uid - 1];
+  return info.uidString;
+}
+uint32_t 
+ChunkRegistry::GetUidFromUidString (std::string uidString)
+{
+  uint32_t uid = 1;
+  InfoVector *vec = GetInfoVector ();
+  for (InfoVector::iterator i = vec->begin (); i != vec->end (); i++)
+    {
+      if (i->uidString == uidString)
+	{
+	  return uid;
+	}
+      uid++;
+    }
+  NS_FATAL_ERROR ("Trying to access a non-registered Header or Trailer: \"" << uidString << "\". "<<
+		  "You could try calling NS_HEADER_ENSURE_REGISTER somewhere.");
+  return 0;
+}
+
+uint8_t *
+ChunkRegistry::GetStaticInstance (uint32_t uid)
+{
+  InfoVector *vec = GetInfoVector ();
+  NS_ASSERT (uid >= 1 && uid <= vec->size ());
+  Info info = (*vec)[uid - 1];
+  return info.getStaticInstance ();
+}
+bool 
+ChunkRegistry::IsHeader (uint32_t uid)
+{
+  InfoVector *vec = GetInfoVector ();
+  NS_ASSERT (uid >= 1 && uid <= vec->size ());
+  Info info = (*vec)[uid - 1];
+  return info.isHeader;
+}
+bool 
+ChunkRegistry::IsTrailer (uint32_t uid)
+{
+  return !IsHeader (uid);
+}
+uint32_t 
+ChunkRegistry::Deserialize (uint32_t uid, uint8_t *instance, Buffer::Iterator i)
+{
+  InfoVector *vec = GetInfoVector ();
+  NS_ASSERT (uid >= 1 && uid <= vec->size ());
+  Info info = (*vec)[uid - 1];
+  return info.deserialize (instance, i);
+}
+void 
+ChunkRegistry::Print (uint32_t uid, uint8_t *instance, std::ostream &os)
+{
+  InfoVector *vec = GetInfoVector ();
+  NS_ASSERT (uid >= 1 && uid <= vec->size ());
+  Info info = (*vec)[uid - 1];
+  return info.print (instance, os);
+}
+std::string
+ChunkRegistry::GetName (uint32_t uid, uint8_t *instance)
+{ 
+  InfoVector *vec = GetInfoVector ();
+  NS_ASSERT (uid >= 1 && uid <= vec->size ());
+  Info info = (*vec)[uid - 1];
+  return info.getName (instance);
+}
+void 
+ChunkRegistry::InvokePrintCallback (uint32_t uid, uint8_t *instance, std::ostream &os,
+				    uint32_t packetUid, uint32_t size, 
+				    Ptr<CallbackImplBase> callback)
+{
+  InfoVector *vec = GetInfoVector ();
+  NS_ASSERT (uid >= 1 && uid <= vec->size ());
+  Info info = (*vec)[uid - 1];
+  info.invokePrintCallback (instance, os, packetUid, size, callback);
+}
+
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/chunk-registry.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,180 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2005 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
+ * 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 CHUNK_REGISTRY_H
+#define CHUNK_REGISTRY_H
+
+#include <stdint.h>
+#include <ostream>
+#include "buffer.h"
+#include "ns3/ptr.h"
+#include "ns3/callback.h"
+
+namespace ns3 {
+
+/**
+ * \brief this registry keeps track of all different
+ * types of headers and trailers and assigns to each of them
+ * a unique integer.
+ * \internal
+ */
+class ChunkRegistry
+{
+public:
+  template <typename T>
+  static uint32_t RegisterHeader (std::string uuid);
+  template <typename T>
+  static uint32_t RegisterTrailer (std::string uuid);
+
+  static std::string GetUidStringFromUid (uint32_t uid);
+  static uint32_t GetUidFromUidString (std::string uidString);
+  static uint8_t *GetStaticInstance (uint32_t uid);
+  static uint32_t Deserialize (uint32_t uid, uint8_t *instance, Buffer::Iterator i);
+  static void Print (uint32_t uid, uint8_t *instance, std::ostream &os);
+  static std::string GetName (uint32_t uid, uint8_t *instance);
+  static bool IsHeader (uint32_t uid);
+  static bool IsTrailer (uint32_t uid);
+  static void InvokePrintCallback (uint32_t uid, uint8_t *instance, std::ostream &os,
+				   uint32_t packetUid, uint32_t size, 
+				   Ptr<CallbackImplBase> callback);
+private:
+  typedef uint8_t *(*GetStaticInstanceCb) (void);
+  typedef uint32_t (*DeserializeCb) (uint8_t *, Buffer::Iterator);
+  typedef void (*PrintCb) (uint8_t *,std::ostream &);
+  typedef std::string (*GetNameCb) (uint8_t *);
+  typedef void (*InvokePrintCallbackCb) (uint8_t *instance, std::ostream &os,
+					 uint32_t packetUid, uint32_t size, 
+					 Ptr<CallbackImplBase> callback);
+  struct Info {
+    std::string uidString;
+    bool isHeader;
+    GetStaticInstanceCb getStaticInstance;
+    DeserializeCb deserialize;
+    PrintCb print;
+    GetNameCb getName;
+    InvokePrintCallbackCb invokePrintCallback;
+  };
+  typedef std::vector<struct Info> InfoVector;
+  static InfoVector *GetInfoVector (void);
+  template <typename T>
+  static uint8_t *DoGetStaticInstance (void);
+  template <typename T>
+  static uint32_t DoDeserialize (uint8_t *instance, Buffer::Iterator i);
+  template <typename T>
+  static void DoPrint (uint8_t *instance, std::ostream &os);
+  template <typename T>
+  static std::string DoGetName (uint8_t *instance);
+  template <typename T>
+  static void DoInvokePrintCallback (uint8_t *instance, std::ostream &os,
+				     uint32_t packetUid, uint32_t size, 
+				     Ptr<CallbackImplBase> callback);
+  template <typename T>
+  static uint32_t GetUid (bool isHeader, std::string uidString);
+
+};
+
+
+} // namespace ns3
+
+namespace ns3 {
+
+template <typename T>
+uint32_t 
+ChunkRegistry::RegisterHeader (std::string uuid)
+{
+  return GetUid<T> (true, uuid);
+}
+template <typename T>
+uint32_t 
+ChunkRegistry::RegisterTrailer (std::string uuid)
+{
+  return GetUid<T> (false, uuid);
+}
+
+template <typename T>
+uint32_t 
+ChunkRegistry::GetUid (bool isHeader, std::string uidString)
+{
+  InfoVector *vec = GetInfoVector ();
+  uint32_t uid = 1; 
+  for (InfoVector::iterator i = vec->begin (); i != vec->end (); i++)
+    {
+      if (i->uidString == uidString)
+	{
+	  return uid;
+	}
+      uid++;
+    }
+  Info info;
+  info.getStaticInstance = &ChunkRegistry::DoGetStaticInstance<T>;
+  info.print = &ChunkRegistry::DoPrint<T>;
+  info.getName = &ChunkRegistry::DoGetName<T>;
+  info.deserialize = &ChunkRegistry::DoDeserialize<T>;
+  info.invokePrintCallback = &ChunkRegistry::DoInvokePrintCallback<T>;
+  info.uidString = uidString;
+  info.isHeader = isHeader;
+  vec->push_back (info);
+  return vec->size ();
+}
+
+template <typename T>
+uint8_t *
+ChunkRegistry::DoGetStaticInstance ()
+{
+  static T instance;
+  return reinterpret_cast<uint8_t *> (&instance);
+}
+template <typename T>
+uint32_t 
+ChunkRegistry::DoDeserialize (uint8_t *instance, Buffer::Iterator i)
+{
+  T *obj = reinterpret_cast<T *> (instance);
+  return obj->Deserialize (i);
+}
+template <typename T>
+void 
+ChunkRegistry::DoPrint (uint8_t *instance, std::ostream &os)
+{
+  T *obj = reinterpret_cast<T *> (instance);
+  obj->Print (os);
+}
+template <typename T>
+std::string
+ChunkRegistry::DoGetName (uint8_t *instance)
+{
+  T *obj = reinterpret_cast<T *> (instance);
+  return obj->GetName ();
+}
+template <typename T>
+void 
+ChunkRegistry::DoInvokePrintCallback (uint8_t *instance, std::ostream &os,
+				      uint32_t packetUid, uint32_t size, 
+				      Ptr<CallbackImplBase> callback)
+{
+  T *obj = reinterpret_cast<T *> (instance);
+  Callback<void,std::ostream&,uint32_t,uint32_t,const T*> cb;
+  cb.Assign (callback);
+  cb (os, packetUid, size, obj);
+}
+
+} // namespace ns3
+
+#endif /* CHUNK_H */
--- a/src/common/chunk.cc	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2005 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
- * 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 "chunk.h"
-#include "ns3/assert.h"
-
-namespace ns3 {
-
-Chunk::Chunk ()
-{}
-
-Chunk::~Chunk ()
-{}
-
-void 
-Chunk::Print (std::ostream &os) const
-{
-  PrintTo (os);
-}
-uint32_t
-Chunk::GetSize (void) const
-{
-  return GetSerializedSize ();
-}
-void
-Chunk::Serialize (Buffer::Iterator start) const
-{
-  SerializeTo (start);
-}
-uint32_t
-Chunk::Deserialize (Buffer::Iterator start)
-{
-  uint32_t deserialized = DeserializeFrom (start);
-  return deserialized;
-}
-std::ostream& operator<< (std::ostream& os, Chunk const& chunk)
-{
-  chunk.Print (os);
-  return os;
-}
-
-}; // namespace ns3
--- a/src/common/chunk.h	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2005 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
- * 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 CHUNK_H
-#define CHUNK_H
-
-#include <stdint.h>
-#include <ostream>
-#include "buffer.h"
-
-namespace ns3 {
-
-class Chunk {
-public:
-  Chunk ();
-  virtual ~Chunk ();
-
-  void Print (std::ostream &os) const;
-  uint32_t GetSize (void) const;
-  void Serialize (Buffer::Iterator start) const;
-  uint32_t Deserialize (Buffer::Iterator start);
-private:
-  virtual void PrintTo (std::ostream &os) const = 0;
-  virtual uint32_t GetSerializedSize (void) const = 0;
-  virtual void SerializeTo (Buffer::Iterator i) const = 0;
-  virtual uint32_t DeserializeFrom (Buffer::Iterator i) = 0;
-};
-
-std::ostream& operator<< (std::ostream& os, Chunk const& chunk);
-
-}; // namespace ns3
-
-#endif /* CHUNK_H */
--- a/src/common/composite-trace-resolver.cc	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,331 +0,0 @@
-/* -*- 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
- * 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 "composite-trace-resolver.h"
-
-namespace ns3 {
-
-CompositeTraceResolver::CompositeTraceResolver (TraceContext const &context)
-  : TraceResolver (context)
-{}
-
-CompositeTraceResolver::~CompositeTraceResolver ()
-{}
-
-void 
-CompositeTraceResolver::DoAdd (std::string name, 
-			       Callback<TraceResolver *,TraceContext const &> createResolver,
-			       TraceContext const &context)
-{
-  struct CallbackTraceSourceItem item;
-  item.name = name;
-  item.createResolver = createResolver;
-  item.context = context;
-  m_items.push_back (item);
-}
-
-TraceResolver::TraceResolverList 
-CompositeTraceResolver::DoLookup (std::string id) const
-{
-  if (id == "*")
-    {
-      TraceResolver::TraceResolverList list;
-      for (TraceItems::const_iterator i = m_items.begin (); i != m_items.end (); i++)
-	{
-	  list.push_back (i->createResolver (i->context));
-	}
-      return list;
-    }
-  std::string::size_type start, end;
-  start = id.find_first_of ("(", 0);
-  end = id.find_first_of (")", 0);
-  if (start != 0 || end != (id.size ()-1))
-    {
-      for (TraceItems::const_iterator i = m_items.begin (); i != m_items.end (); i++)
-	{
-	  if (i->name == id)
-	    {
-	      TraceResolver::TraceResolverList list;
-	      list.push_back (i->createResolver (i->context));
-	      return list;
-	    }
-	}
-    }
-  std::list<std::string> names;
-  std::string alternatives = std::string (id, start+1, end-1);
-  std::string::size_type next, cur;
-  next = 0;
-  cur = 0;
-  while (true)
-    {
-      std::string element;
-      next = alternatives.find ("|", cur);
-      if (next == std::string::npos)
-	{
-	  element = std::string (alternatives, cur, alternatives.size ());
-	  names.push_back (element);
-	  break;
-	}
-      element = std::string (alternatives, cur, next);
-      names.push_back (element);
-      cur = next + 1;
-    }
-  TraceResolver::TraceResolverList list;
-  for (std::list<std::string>::const_iterator i = names.begin (); i != names.end (); i++)
-    {
-      for (TraceItems::const_iterator j = m_items.begin (); j != m_items.end (); j++)
-	{
-	  if (j->name == *i)
-	    {
-	      list.push_back (j->createResolver (j->context));
-	      break;
-	    }
-	}
-    }
-  return list;
-}
-
-}//namespace ns3
-
-#ifdef RUN_SELF_TESTS
-
-#include "ns3/test.h"
-
-namespace ns3 {
-
-class CompositeTraceResolverTest : public Test
-{
-public:
-  enum TraceSources {
-    TEST_TRACE_DOUBLEA,
-    TEST_TRACE_DOUBLEB,
-    TEST_TRACE_SUBRESOLVER,
-  };
-  enum SubTraceSources {
-    TEST_SUBTRACE_INT,
-  };
-  CompositeTraceResolverTest ();
-  virtual ~CompositeTraceResolverTest ();
-  virtual bool RunTests (void);
-private:
-  void TraceDouble (TraceContext const &context, double v);
-  void TraceInt (TraceContext const &context, int v);
-  TraceResolver *CreateSubResolver (TraceContext const &context);
-
-
-  bool m_gotDoubleA;
-  bool m_gotDoubleB;
-  CallbackTraceSource<int> m_traceInt;
-  bool m_gotInt;
-};
-
-CompositeTraceResolverTest::CompositeTraceResolverTest ()
-  : Test ("CompositeTraceResolver")
-{}
-CompositeTraceResolverTest::~CompositeTraceResolverTest ()
-{}
-void 
-CompositeTraceResolverTest::TraceDouble (TraceContext const &context, double v)
-{
-  enum CompositeTraceResolverTest::TraceSources source;
-  context.Get (source);
-  switch (source)
-    {
-    case TEST_TRACE_DOUBLEA:
-      m_gotDoubleA = true;
-      break;
-    case TEST_TRACE_DOUBLEB:
-      m_gotDoubleB = true;
-      break;
-    default:
-      NS_FATAL_ERROR ("should not get any other trace source in this sink");
-      break;
-    }
-  
-}
-
-void 
-CompositeTraceResolverTest::TraceInt (TraceContext const &context, int v)
-{
-  m_gotInt = true;
-}
-
-TraceResolver *
-CompositeTraceResolverTest::CreateSubResolver (TraceContext const &context)
-{
-  CompositeTraceResolver *subresolver = new CompositeTraceResolver (context);
-  subresolver->Add ("trace-int", m_traceInt, TEST_SUBTRACE_INT);
-  return subresolver;
-}
-bool 
-CompositeTraceResolverTest::RunTests (void)
-{
-  bool ok = true;
-
-  CallbackTraceSource<double> traceDoubleA;
-  CallbackTraceSource<double> traceDoubleB;
-  TraceContext context;
-
-  CompositeTraceResolver resolver (context) ;
-
-  resolver.Add ("trace-double-a", traceDoubleA, TEST_TRACE_DOUBLEA);
-  resolver.Add ("trace-double-b", traceDoubleB, TEST_TRACE_DOUBLEB);
-
-  resolver.Connect ("/*", MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
-
-  m_gotDoubleA = false;
-  m_gotDoubleB = false;
-  traceDoubleA (0);
-  if (!m_gotDoubleA || m_gotDoubleB)
-    {
-      ok = false;
-    }
-  m_gotDoubleA = false;
-  traceDoubleA (0);
-  traceDoubleB (0);
-  if (!m_gotDoubleA || !m_gotDoubleB)
-    {
-      ok = false;
-    }
-  m_gotDoubleA = false;
-  m_gotDoubleB = false;
-
-  resolver.Disconnect ("/*", MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
-
-  m_gotDoubleA = false;
-  m_gotDoubleB = false;
-  traceDoubleA (0);
-  traceDoubleB (0);
-  if (m_gotDoubleA || m_gotDoubleB)
-    {
-      ok = false;
-    }
-
-  resolver.Connect ("/trace-double-a", 
-		    MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
-  m_gotDoubleA = false;
-  m_gotDoubleB = false;
-  traceDoubleA (0);
-  traceDoubleB (0);
-  if (!m_gotDoubleA || m_gotDoubleB)
-    {
-      ok = false;
-    }
-  resolver.Disconnect ("/trace-double-a", 
-		       MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
-
-  resolver.Connect ("/(trace-double-a)", 
-		    MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
-  m_gotDoubleA = false;
-  m_gotDoubleB = false;
-  traceDoubleA (0);
-  traceDoubleB (0);
-  if (!m_gotDoubleA || m_gotDoubleB)
-    {
-      ok = false;
-    }
-  resolver.Disconnect ("/trace-double-a", 
-		       MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
-
-  resolver.Connect ("/(trace-double-a|trace-double-b)", 
-		    MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
-  m_gotDoubleA = false;
-  m_gotDoubleB = false;
-  traceDoubleA (0);
-  traceDoubleB (0);
-  if (!m_gotDoubleA || !m_gotDoubleB)
-    {
-      ok = false;
-    }
-  resolver.Disconnect ("/trace-double-a", 
-		       MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
-  m_gotDoubleA = false;
-  m_gotDoubleB = false;
-  traceDoubleA (0);
-  traceDoubleB (0);
-  if (m_gotDoubleA || !m_gotDoubleB)
-    {
-      ok = false;
-    }
-
-
-  resolver.Disconnect ("/(trace-double-a|trace-double-b)", 
-		       MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
-  m_gotDoubleA = false;
-  m_gotDoubleB = false;
-  traceDoubleA (0);
-  traceDoubleB (0);
-  if (m_gotDoubleA || m_gotDoubleB)
-    {
-      ok = false;
-    }
-
-  resolver.Add ("subresolver", 
-		MakeCallback (&CompositeTraceResolverTest::CreateSubResolver, this),
-		TEST_TRACE_SUBRESOLVER);
-
-  resolver.Connect ("/subresolver/trace-int", 
-		    MakeCallback (&CompositeTraceResolverTest::TraceInt, this));
-  m_gotInt = false;
-  m_traceInt (1);
-  if (!m_gotInt)
-    {
-      ok = false;
-    }
-
-  resolver.Disconnect ("/subresolver/trace-int", 
-		       MakeCallback (&CompositeTraceResolverTest::TraceInt, this));
-  m_gotInt = false;
-  m_traceInt (1);
-  if (m_gotInt)
-    {
-      ok = false;
-    }
-
-  resolver.Connect ("/*/trace-int", 
-		    MakeCallback (&CompositeTraceResolverTest::TraceInt, this));
-  m_gotInt = false;
-  m_traceInt (1);
-  if (!m_gotInt)
-    {
-      ok = false;
-    }
-
-  resolver.Disconnect ("/subresolver/trace-int", 
-		       MakeCallback (&CompositeTraceResolverTest::TraceInt, this));
-  m_gotInt = false;
-  m_traceInt (1);
-  if (m_gotInt)
-    {
-      ok = false;
-    }
-
-
-  
-
-  return ok;
-}
-
-static CompositeTraceResolverTest g_compositeTraceResolverTest;
-
-}//namespace ns3
-
-
-#endif /* RUN_SELF_TESTS */
--- a/src/common/composite-trace-resolver.h	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,211 +0,0 @@
-/* -*- 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
- * 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 COMPOSITE_TRACE_RESOLVER_H
-#define COMPOSITE_TRACE_RESOLVER_H
-
-#include "ns3/callback.h"
-#include "trace-resolver.h"
-#include "callback-trace-source.h"
-#include "uv-trace-source.h"
-#include "sv-trace-source.h"
-#include "fv-trace-source.h"
-#include "terminal-trace-resolver.h"
-
-namespace ns3 {
-
-/**
- * \brief a helper class to aggregate contained TraceResolver and other trace sources.
- * \ingroup lowleveltracing
- */
-class CompositeTraceResolver : public TraceResolver
-{
-public:
-  CompositeTraceResolver (TraceContext const &context);
-  virtual ~CompositeTraceResolver ();
-  /**
-   * \param name name of trace source
-   * \param trace a callback trace source
-   * \param context the context associated to this trace source
-   *
-   * Add a callback trace source in this resolver. This trace
-   * source will match the name specified during namespace 
-   * resolution. The TraceContext of this trace source will also
-   * be automatically extended to contain the input context.
-   */
-  template <typename T1, typename T2,
-            typename T3, typename T4,
-            typename T>
-  void Add (std::string name,
-            CallbackTraceSource<T1,T2,T3,T4> &trace, T const &context);
-  /**
-   * \param name name of trace source
-   * \param trace a signed variable trace source
-   * \param context the context associated to this trace source
-   *
-   * Add a signed variable trace source in this resolver. 
-   * This trace source will match the name specified during namespace 
-   * resolution. The TraceContext of this trace source will also
-   * be automatically extended to contain the input context.
-   */
-  template <typename T>
-  void Add (std::string name,
-            SVTraceSource<T> &trace, T const &context);
-  /**
-   * \param name name of trace source
-   * \param trace an unsigned variable trace source
-   * \param context the context associated to this trace source
-   *
-   * Add an unsigned variable trace source in this resolver. 
-   * This trace source will match the name specified during namespace 
-   * resolution. The TraceContext of this trace source will also
-   * be automatically extended to contain the input context.
-   */
-  template <typename T>
-  void Add (std::string name,
-            UVTraceSource<T> &trace, T const &context);
-  /**
-   * \param name name of trace source
-   * \param trace a floating-point variable trace source
-   * \param context the context associated to this trace source
-   *
-   * Add a floating-point variable trace source in this resolver. 
-   * This trace source will match the name specified during namespace 
-   * resolution. The TraceContext of this trace source will also
-   * be automatically extended to contain the input context.
-   */
-  template <typename T>
-  void Add (std::string name,
-            FVTraceSource<T> &trace, T const &context);
-
-  /**
-   * \param name name of child trace resolver
-   * \param createResolver a trace resolver constructor
-   * \param context the context associated to this entry
-   *
-   * Add a child trace resolver to this resolver. This child
-   * trace resolver will match the name specified during
-   * namespace resolution. When this happens, the constructor
-   * will be invoked to create the child trace resolver and
-   * the associated TraceContext will be automatically extended
-   * to contain the input context.
-   */
-  template <typename T>
-  void Add (std::string name, 
-            Callback<TraceResolver *,TraceContext const &> createResolver,
-            T const &context);
-private:
-  template <typename SOURCE, typename CONTEXT>
-  void DoAddTraceSource (std::string name,
-                         SOURCE &traceSource, CONTEXT const &context);
-  template <typename SOURCE>
-  static TraceResolver *CreateTerminalTraceResolver (SOURCE *trace, 
-                                                     TraceContext const &context);
-  void DoAdd (std::string name, 
-              Callback<TraceResolver *,TraceContext const &> createResolver,
-              TraceContext const &context);
-  virtual TraceResolverList DoLookup (std::string id) const;
-
-  struct CallbackTraceSourceItem
-  {
-    std::string name;
-    Callback<TraceResolver *,TraceContext const &> createResolver;
-    TraceContext context;
-  };
-
-  typedef std::list<struct CallbackTraceSourceItem> TraceItems;
-  TraceItems m_items;
-};
-
-}//namespace ns3
-
-namespace ns3 {
-
-template <typename SOURCE, typename CONTEXT>
-void 
-CompositeTraceResolver::DoAddTraceSource (std::string name,
-                                          SOURCE &traceSource, CONTEXT const &context)
-{
-  TraceContext traceContext = GetContext ();
-  traceContext.Add (context);
-  TraceResolver *(*create) (SOURCE *trace, TraceContext const &context);
-  create = &CompositeTraceResolver::CreateTerminalTraceResolver<SOURCE>;
-  Callback<TraceResolver *,TraceContext const &> createResolver = 
-    MakeBoundCallback (create, &traceSource);
-  DoAdd (name, createResolver, traceContext);
-}
-
-template <typename SOURCE>
-TraceResolver *
-CompositeTraceResolver::CreateTerminalTraceResolver (SOURCE *traceSource, 
-                                                     TraceContext const &context)
-{
-  return new TerminalTraceResolver<SOURCE> (*traceSource, context);
-}
-
-
-
-
-template <typename T1, typename T2,
-          typename T3, typename T4,
-          typename T>
-void 
-CompositeTraceResolver::Add (std::string name,
-                             CallbackTraceSource<T1,T2,T3,T4> &trace, 
-                             T const &context)
-{
-  DoAddTraceSource (name, trace, context);
-}
-template <typename T>
-void 
-CompositeTraceResolver::Add (std::string name,
-                             SVTraceSource<T> &trace, T const &context)
-{
-  DoAddTraceSource (name, trace, context);
-}
-template <typename T>
-void 
-CompositeTraceResolver::Add (std::string name,
-                             UVTraceSource<T> &trace, T const &context)
-{
-  DoAddTraceSource (name, trace, context);
-}
-template <typename T>
-void 
-CompositeTraceResolver::Add (std::string name,
-                             FVTraceSource<T> &trace, T const &context)
-{
-  DoAddTraceSource (name, trace, context);
-}
-template <typename T>
-void 
-CompositeTraceResolver::Add (std::string name, 
-                             Callback<TraceResolver *,TraceContext const &> createResolver,
-                             T const &context)
-{
-  TraceContext traceContext = GetContext ();
-  traceContext.Add (context);
-  DoAdd (name, createResolver, traceContext);
-}
-
-
-}//namespace ns3
-
-#endif /* COMPOSITE_TRACE_RESOLVER_H */
--- a/src/common/data-rate.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/common/data-rate.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -23,9 +23,8 @@
 #include "ns3/nstime.h"
 #include "ns3/fatal-error.h"
 
-namespace {
 
-bool
+static bool
 DoParse (const std::string s, uint64_t *v)
 {
   std::string::size_type n = s.find_first_not_of("0123456789.");
@@ -123,7 +122,6 @@
   return true;
 }
 
-}
 
 namespace ns3 {
 
--- a/src/common/empty-trace-resolver.cc	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-/* -*- 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
- * 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 "empty-trace-resolver.h"
-
-ns3::EmptyTraceResolver::EmptyTraceResolver (TraceContext const &context)
-  : TraceResolver (context)
-{}
--- a/src/common/empty-trace-resolver.h	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-/* -*- 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
- * 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 EMPTY_TRACE_RESOLVER_H
-#define EMPTY_TRACE_RESOLVER_H
-
-#include "trace-resolver.h"
-
-namespace ns3 {
-
-class TraceContext;
-
-/**
- * \brief a TraceResolver instance which does not resolve anything.
- * \ingroup tracing
- *
- * Trying to resolve against this class will yield no matches and no
- * connections. Returning an instance of this class from a 
- * CreateTraceResolver method is a hand way of not implementing
- * any Tracing code.
- */
-class EmptyTraceResolver : public TraceResolver
-{
-public:
-  /**
-   * \param o necessary context for this class.
-   *
-   * The only constructor exported by this class.
-   */
-  EmptyTraceResolver (TraceContext const &o);
-};
-
-}//namespace ns3
-
-#endif /* EMPTY_TRACE_RESOLVER_H */
--- a/src/common/fv-trace-source.h	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2006 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
- * 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 F_VARIABLE_TRACER_H
-#define F_VARIABLE_TRACER_H
-
-#include "callback-trace-source.h"
-#include <stdint.h>
-
-namespace ns3 {
-
-class FVTraceSourceBase {
-public:
-  typedef CallbackTraceSource<double, double> ChangeNotifyCallback;
-
-  FVTraceSourceBase () {}
-  FVTraceSourceBase (FVTraceSourceBase const &o) {}
-  FVTraceSourceBase &operator = (FVTraceSourceBase const &o) {
-      return *this;
-  }
-
-  ~FVTraceSourceBase () {}
-
-  void AddCallback (CallbackBase const & callback, TraceContext const & context) {
-    m_callback.AddCallback (callback, context);
-  }
-  void RemoveCallback (CallbackBase const & callback) {
-    m_callback.RemoveCallback (callback);
-  }
-protected:
-  void notify (double oldVal, double newVal) {
-      if (oldVal != newVal) 
-        {
-          m_callback (oldVal, newVal);
-        }
-  }
-private:
-  ChangeNotifyCallback m_callback;
-};
-
-template <typename T>
-class FVTraceSource : public FVTraceSourceBase 
-{
-public:
-};
-
-}; // namespace ns3
-
-#endif /* F_VARIABLE_TRACER_H */
--- a/src/common/header.cc	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2005 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
- * 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 "header.h"
-
-namespace ns3 {
-
-Header::~Header ()
-{}
-
-}; // namespace ns3
--- a/src/common/header.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/common/header.h	Fri Sep 28 11:59:46 2007 +0100
@@ -22,7 +22,29 @@
 #ifndef HEADER_H
 #define HEADER_H
 
-#include "chunk.h"
+#include "chunk-registry.h"
+
+/**
+ * \relates ns3::Header
+ * \brief this macro should be instantiated exactly once for each
+ *        new type of Header
+ *
+ * This macro will ensure that your new Header type is registered
+ * within the packet header registry. In most cases, this macro
+ * is not really needed but, for safety, please, use it all the
+ * time.
+ *
+ * Note: This macro is _absolutely_ needed if you try to run a
+ * distributed simulation.
+ */
+#define NS_HEADER_ENSURE_REGISTERED(x)         \
+static class thisisaveryverylongclassname ##x  \
+{                                              \
+ public:                                       \
+  thisisaveryverylongclassname ##x ()          \
+    { uint32_t uid; uid = x::GetUid ();}       \
+} g_thisisanotherveryveryverylongname ## x;
+
 
 namespace ns3 {
 
@@ -30,51 +52,64 @@
  * \brief Protocol header serialization and deserialization.
  *
  * Every Protocol header which needs to be inserted or removed
- * from a Packet instance must derive from this abstract base class
- * and implement the private pure virtual methods listed below:
- *   - ns3::Header::SerializeTo
- *   - ns3::Header::DeserializeFrom
- *   - ns3::Header::GetSerializedSize
- *   - ns3::Header::PrintTo
+ * from a Packet instance must derive from this base class and
+ * implement the following public methods:
+ *   - a default constructor: is used by the internal implementation
+ *     if the Packet class.
+ *   - a static method named GetUid: is used to uniquely identify
+ *     the type of each header. This method shall return a unique
+ *     integer allocated with Header::AllocateUid.
+ *   - a method named Serialize: is used by Packet::AddHeader to
+ *     store a header into the byte buffer of a packet.
+ *     The input iterator points to the start of the byte buffer in
+ *     which the header should write its data. The data written
+ *     is expected to match bit-for-bit the representation of this
+ *     header in a real network.
+ *   - a method named GetSerializedSize: is used by Packet::AddHeader
+ *     to store a header into the byte buffer of a packet. This method
+ *     should return the number of bytes which are needed to store
+ *     the full header data by Serialize.
+ *   - a method named Deserialize: is used by Packet::RemoveHeader to
+ *     re-create a header from the byte buffer of a packet. The input
+ *     iterator points to the start of the byte buffer from which
+ *     the header should read its data. The data read is expected to
+ *     match bit-for-bit the representation of this header in real
+ *     networks. This method shall return an integer which identifies
+ *     the number of bytes read.
+ *   - a method named Print: is used by Packet::Print to print the 
+ *     content of a header as ascii data to a c++ output stream.
+ *     Although the header is free to format its output as it
+ *     wishes, it is recommended to follow a few rules to integrate
+ *     with the packet pretty printer: start with flags, small field 
+ *     values located between a pair of parens. Values should be separated 
+ *     by whitespace. Follow the parens with the important fields, 
+ *     separated by whitespace.
+ *     i.e.: (field1 val1 field2 val2 field3 val3) field4 val4 field5 val5
+ *   - a method named GetName: is used by Packet::Print to print
+ *     header fragments. This method should return a user-readable
+ *     single word as all capitalized letters.
+ *
+ * Sample code which shows how to create a new type of Header, and how to use it, 
+ * is shown in the sample file samples/main-packet-header.cc
  */
-class Header : public Chunk {
-public:
-  virtual ~Header ();
-private:
-  /**
-   * \param os the std output stream in which this 
-   *       protocol header must print itself.
-   */
-  virtual void PrintTo (std::ostream &os) const = 0;
-
-  /**
-   * \returns the size of the serialized Header.
-   *
-   * This method is used by Packet::AddHeader to reserve
-   * enough room in the packet byte buffer prior to calling
-   * Header::Serialize.
-   */
-  virtual uint32_t GetSerializedSize (void) const = 0;
-
-  /**
-   * \param start the buffer iterator in which the protocol header
-   *    must serialize itself. This iterator identifies 
-   *    the start of the buffer.
-   */
-  virtual void SerializeTo (Buffer::Iterator start) const = 0;
-  /**
-   * \param start the buffer iterator from which the protocol header must
-   *    deserialize itself. This iterator identifies 
-   *    the start of the buffer.
-   * \returns the number of bytes read from the buffer
-   *
-   * The value returned is used to trim the packet byte buffer of the 
-   * corresponding amount when this method is invoked from 
-   * Packet::RemoveHeader
-   */
-  virtual uint32_t DeserializeFrom (Buffer::Iterator start) = 0;
+class Header 
+{
+protected:
+  template <typename T>
+  static uint32_t AllocateUid (std::string uuid);
 };
 
-}; // namespace ns3
+} // namespace ns3
+
+namespace ns3 {
+
+template <typename T>
+uint32_t 
+Header::AllocateUid (std::string uuid)
+{
+  return ChunkRegistry::RegisterHeader<T> (uuid);
+}
+
+} // namespace ns3
 
 #endif /* HEADER_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/packet-metadata-test.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,690 @@
+/* -*- 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>
+ */
+#ifdef RUN_SELF_TESTS
+
+#include <stdarg.h>
+#include <iostream>
+#include <sstream>
+#include "ns3/test.h"
+#include "header.h"
+#include "trailer.h"
+#include "packet.h"
+#include "packet-metadata.h"
+#include "packet-printer.h"
+
+namespace ns3 {
+
+template <int N>
+class HistoryHeader : public Header
+{
+public:
+  static uint32_t GetUid (void);
+  HistoryHeader ();
+  bool IsOk (void) const;
+  std::string GetName (void) const;
+  void Print (std::ostream &os) const;
+  uint32_t GetSerializedSize (void) const;
+  void Serialize (Buffer::Iterator start) const;
+  uint32_t Deserialize (Buffer::Iterator start);
+private:
+  bool m_ok;
+};
+
+template <int N>
+uint32_t
+HistoryHeader<N>::GetUid (void)
+{
+  std::ostringstream oss;
+  oss << N << "HistoryHeader.ns3";
+  static uint32_t uid = AllocateUid<HistoryHeader<N> > (oss.str());
+  return uid;
+}
+
+template <int N>
+HistoryHeader<N>::HistoryHeader ()
+  : m_ok (false)
+{}
+
+template <int N>
+bool 
+HistoryHeader<N>::IsOk (void) const
+{
+  return m_ok;
+}
+
+template <int N>
+std::string 
+HistoryHeader<N>::GetName (void) const
+{
+  std::ostringstream oss;
+  oss << N;
+  return oss.str ();
+}
+
+template <int N>
+void 
+HistoryHeader<N>::Print (std::ostream &os) const
+{
+  NS_ASSERT (false);
+}
+template <int N>
+uint32_t 
+HistoryHeader<N>::GetSerializedSize (void) const
+{
+  return N;
+}
+template <int N>
+void 
+HistoryHeader<N>::Serialize (Buffer::Iterator start) const
+{
+  start.WriteU8 (N, N);
+}
+template <int N>
+uint32_t
+HistoryHeader<N>::Deserialize (Buffer::Iterator start)
+{
+  m_ok = true;
+  for (int i = 0; i < N; i++)
+    {
+      if (start.ReadU8 () != N)
+        {
+          m_ok = false;
+        }
+    }
+  return N;
+}
+
+template <int N>
+class HistoryTrailer : public Trailer
+{
+public:
+  static uint32_t GetUid (void);
+  HistoryTrailer ();
+  bool IsOk (void) const;
+  std::string GetName (void) const;
+  void Print (std::ostream &os) const;
+  uint32_t GetSerializedSize (void) const;
+  void Serialize (Buffer::Iterator start) const;
+  uint32_t Deserialize (Buffer::Iterator start);
+private:
+  bool m_ok;
+};
+
+template <int N>
+uint32_t
+HistoryTrailer<N>::GetUid (void)
+{
+  std::ostringstream oss;
+  oss << N << "HistoryTrailer.ns3";
+  static uint32_t uid = AllocateUid<HistoryTrailer<N> > (oss.str ());
+  return uid;
+}
+
+
+template <int N>
+HistoryTrailer<N>::HistoryTrailer ()
+  : m_ok (false)
+{}
+
+template <int N>
+bool
+HistoryTrailer<N>::IsOk (void) const
+{
+  return m_ok;
+}
+
+template <int N>
+std::string 
+HistoryTrailer<N>::GetName (void) const
+{
+  std::ostringstream oss;
+  oss << N;
+  return oss.str ();
+}
+template <int N>
+void 
+HistoryTrailer<N>::Print (std::ostream &os) const
+{
+  NS_ASSERT (false);
+}
+template <int N>
+uint32_t 
+HistoryTrailer<N>::GetSerializedSize (void) const
+{
+  return N;
+}
+template <int N>
+void 
+HistoryTrailer<N>::Serialize (Buffer::Iterator start) const
+{
+  start.Prev (N);
+  start.WriteU8 (N, N);
+}
+template <int N>
+uint32_t
+HistoryTrailer<N>::Deserialize (Buffer::Iterator start)
+{
+  m_ok = true;
+  start.Prev (N);
+  for (int i = 0; i < N; i++)
+    {
+      if (start.ReadU8 () != N)
+        {
+          m_ok = false;
+        }
+    }
+  return N;
+}
+
+
+
+class PacketMetadataTest : public Test {
+public:
+  PacketMetadataTest ();
+  virtual ~PacketMetadataTest ();
+  bool CheckHistory (Packet p, const char *file, int line, uint32_t n, ...);
+  virtual bool RunTests (void);
+private:
+  template <int N>
+  void PrintHeader (std::ostream &os, uint32_t packetUid, uint32_t size, const HistoryHeader<N> *header);
+  template <int N>
+  void PrintTrailer (std::ostream &os, uint32_t packetUid, uint32_t size, const HistoryTrailer<N> *trailer);
+  void PrintFragment (std::ostream &os,uint32_t packetUid,
+                      uint32_t size,std::string & name, 
+                      struct PacketPrinter::FragmentInformation info);
+  void PrintPayload (std::ostream &os,uint32_t packetUid,
+                     uint32_t size,
+                     struct PacketPrinter::FragmentInformation info);
+  template <int N>
+  void RegisterHeader (void);
+  template <int N>
+  void RegisterTrailer (void);
+  void CleanupPrints (void);
+  Packet DoAddHeader (Packet p);
+  bool Check (const char *file, int line, std::list<int> expected);
+
+
+  bool m_headerError;
+  bool m_trailerError;
+  std::list<int> m_prints;
+  PacketPrinter m_printer;
+};
+
+PacketMetadataTest::PacketMetadataTest ()
+  : Test ("PacketMetadata")
+{
+  m_printer.SetPayloadPrinter (MakeCallback (&PacketMetadataTest::PrintPayload, this));
+  m_printer.SetSeparator ("");
+}
+
+PacketMetadataTest::~PacketMetadataTest ()
+{}
+
+template <int N>
+void 
+PacketMetadataTest::RegisterHeader (void)
+{
+  static bool registered = false;
+  if (!registered)
+    {
+      m_printer.SetHeaderPrinter (MakeCallback (&PacketMetadataTest::PrintHeader<N>, this),
+                                  MakeCallback (&PacketMetadataTest::PrintFragment, this));
+      registered = true;
+    }
+}
+
+template <int N>
+void 
+PacketMetadataTest::RegisterTrailer (void)
+{
+  static bool registered = false;
+  if (!registered)
+    {
+      m_printer.SetTrailerPrinter (MakeCallback (&PacketMetadataTest::PrintTrailer<N>, this),
+                                   MakeCallback (&PacketMetadataTest::PrintFragment, this));
+      registered = true;
+    }
+}
+
+
+template <int N>
+void 
+PacketMetadataTest::PrintHeader (std::ostream &os, uint32_t packetUid, uint32_t size, 
+                                const HistoryHeader<N> *header)
+{
+  if (!header->IsOk ())
+    {
+      m_headerError = true;
+    }
+  m_prints.push_back (N);
+}
+
+template <int N>
+void 
+PacketMetadataTest::PrintTrailer (std::ostream &os, uint32_t packetUid, uint32_t size, 
+                                 const HistoryTrailer<N> *trailer)
+{
+  if (!trailer->IsOk ())
+    {
+      m_trailerError = true;
+    }
+  m_prints.push_back (N);
+}
+void 
+PacketMetadataTest::PrintFragment (std::ostream &os,uint32_t packetUid,
+                                  uint32_t size,std::string & name, 
+                                  struct PacketPrinter::FragmentInformation info)
+{
+  m_prints.push_back (size - (info.end + info.start));
+}
+void 
+PacketMetadataTest::PrintPayload (std::ostream &os,uint32_t packetUid,
+                                 uint32_t size,
+                                 struct PacketPrinter::FragmentInformation info)
+{
+  m_prints.push_back (size - (info.end + info.start));
+}
+
+
+void 
+PacketMetadataTest::CleanupPrints (void)
+{
+  m_prints.clear ();
+}
+
+bool
+PacketMetadataTest::Check (const char *file, int line, std::list<int> expected)
+{
+  if (m_headerError)
+    {
+      Failure () << "PacketMetadata header error. file=" << file 
+                << ", line=" << line << std::endl;
+      return false;
+    }
+  if (m_trailerError)
+    {
+      Failure () << "PacketMetadata trailer error. file=" << file 
+                << ", line=" << line << std::endl;
+      return false;
+    }
+  if (expected.size () != m_prints.size ())
+    {
+      goto error;
+    }
+  for (std::list<int>::iterator i = m_prints.begin (),
+         j = expected.begin (); 
+       i != m_prints.end (); i++, j++)
+    {
+      NS_ASSERT (j != expected.end ());
+      if (*j != *i)
+        {
+          goto error;
+        }
+    }
+  return true;
+ error:
+  Failure () << "PacketMetadata error. file="<< file 
+            << ", line=" << line << ", got:\"";
+  for (std::list<int>::iterator i = m_prints.begin (); 
+       i != m_prints.end (); i++)
+    {
+      Failure () << *i << ", ";
+    }
+  Failure () << "\", expected: \"";
+  for (std::list<int>::iterator j = expected.begin ();
+       j != expected.end (); j++)
+    {
+      Failure () << *j << ", ";
+    }
+  Failure () << "\"" << std::endl;
+  return false;
+}
+
+bool 
+PacketMetadataTest::CheckHistory (Packet p, const char *file, int line, uint32_t n, ...)
+{
+  m_headerError = false;
+  m_trailerError = false;
+  std::list<int> expected;
+  va_list ap;
+  va_start (ap, n);
+  for (uint32_t j = 0; j < n; j++)
+    {
+      int v = va_arg (ap, int);
+      expected.push_back (v);
+    }
+  va_end (ap);
+
+  m_printer.PrintForward ();
+  p.Print (Failure (), m_printer);
+  bool ok = Check (file, line, expected);
+  CleanupPrints ();
+  if (!ok)
+    {
+      return false;
+    }
+
+  m_printer.PrintBackward ();
+  p.Print (Failure (), m_printer);
+  expected.reverse ();
+  ok = Check (file, line, expected);
+  CleanupPrints ();
+  return ok;
+}
+
+#define ADD_HEADER(p, n)                        \
+  {                                             \
+    HistoryHeader<n> header;                    \
+    RegisterHeader<n> ();                       \
+    p.AddHeader (header);                       \
+  }
+#define ADD_TRAILER(p, n)                       \
+  {                                             \
+    HistoryTrailer<n> trailer;                  \
+    RegisterTrailer<n> ();                      \
+    p.AddTrailer (trailer);                     \
+  }
+#define REM_HEADER(p, n)                        \
+  {                                             \
+    HistoryHeader<n> header;                    \
+    RegisterHeader<n> ();                       \
+    p.RemoveHeader (header);                    \
+  }
+#define REM_TRAILER(p, n)                       \
+  {                                             \
+    HistoryTrailer<n> trailer;                  \
+    RegisterTrailer<n> ();                      \
+    p.RemoveTrailer (trailer);                  \
+  }
+#define CHECK_HISTORY(p, ...)                   \
+  {                                             \
+    if (!CheckHistory (p, __FILE__,             \
+                      __LINE__, __VA_ARGS__))   \
+      {                                         \
+        ok = false;                             \
+      }                                         \
+    Buffer buffer;                              \
+    buffer = p.Serialize ();                    \
+    Packet otherPacket;                         \
+    otherPacket.Deserialize  (buffer);          \
+    if (!CheckHistory (otherPacket, __FILE__,   \
+                      __LINE__, __VA_ARGS__))   \
+      {                                         \
+        ok = false;                             \
+      }                                         \
+  }
+
+
+Packet 
+PacketMetadataTest::DoAddHeader (Packet p)
+{
+  ADD_HEADER (p, 10);
+  return p;
+}
+
+bool
+PacketMetadataTest::RunTests (void)
+{
+  bool ok = true;
+
+  PacketMetadata::Enable ();
+
+  Packet p = Packet (0);
+  Packet p1 = Packet (0);
+
+  p = Packet (10);
+  ADD_TRAILER (p, 100);
+  CHECK_HISTORY (p, 2, 10, 100);
+
+  p = Packet (10);
+  ADD_HEADER (p, 1);
+  ADD_HEADER (p, 2);
+  ADD_HEADER (p, 3);
+  CHECK_HISTORY (p, 4, 
+                 3, 2, 1, 10);
+  ADD_HEADER (p, 5);
+  CHECK_HISTORY (p, 5, 
+                 5, 3, 2, 1, 10);
+  ADD_HEADER (p, 6);
+  CHECK_HISTORY (p, 6, 
+                 6, 5, 3, 2, 1, 10);
+
+  p = Packet (10);
+  ADD_HEADER (p, 1);
+  ADD_HEADER (p, 2);
+  ADD_HEADER (p, 3);
+  REM_HEADER (p, 3);
+  CHECK_HISTORY (p, 3, 
+                 2, 1, 10);
+
+  p = Packet (10);
+  ADD_HEADER (p, 1);
+  ADD_HEADER (p, 2);
+  ADD_HEADER (p, 3);
+  REM_HEADER (p, 3);
+  REM_HEADER (p, 2);
+  CHECK_HISTORY (p, 2, 
+                 1, 10);
+
+  p = Packet (10);
+  ADD_HEADER (p, 1);
+  ADD_HEADER (p, 2);
+  ADD_HEADER (p, 3);
+  REM_HEADER (p, 3);
+  REM_HEADER (p, 2);
+  REM_HEADER (p, 1);
+  CHECK_HISTORY (p, 1, 10);
+
+  p = Packet (10);
+  ADD_HEADER (p, 1);
+  ADD_HEADER (p, 2);
+  ADD_HEADER (p, 3);
+  p1 = p;
+  REM_HEADER (p1, 3);
+  REM_HEADER (p1, 2);
+  REM_HEADER (p1, 1);
+  CHECK_HISTORY (p1, 1, 10);
+  CHECK_HISTORY (p, 4, 
+                 3, 2, 1, 10);
+  ADD_HEADER (p1, 1);
+  ADD_HEADER (p1, 2);
+  CHECK_HISTORY (p1, 3, 
+                 2, 1, 10);
+  CHECK_HISTORY (p, 4, 
+                 3, 2, 1, 10);
+  ADD_HEADER (p, 3);
+  CHECK_HISTORY (p, 5, 
+                 3, 3, 2, 1, 10);
+  ADD_TRAILER (p, 4);
+  CHECK_HISTORY (p, 6, 
+                 3, 3, 2, 1, 10, 4);
+  ADD_TRAILER (p, 5);
+  CHECK_HISTORY (p, 7, 
+                 3, 3, 2, 1, 10, 4, 5);
+  REM_HEADER (p, 3);
+  CHECK_HISTORY (p, 6, 
+                 3, 2, 1, 10, 4, 5);
+  REM_TRAILER (p, 5);
+  CHECK_HISTORY (p, 5, 
+                 3, 2, 1, 10, 4);
+  p1 = p;
+  REM_TRAILER (p, 4);
+  CHECK_HISTORY (p, 4, 
+                 3, 2, 1, 10);
+  CHECK_HISTORY (p1, 5, 
+                 3, 2, 1, 10, 4);
+  p1.RemoveAtStart (3);
+  CHECK_HISTORY (p1, 4, 
+                 2, 1, 10, 4);
+  p1.RemoveAtStart (1);
+  CHECK_HISTORY (p1, 4, 
+                 1, 1, 10, 4);
+  p1.RemoveAtStart (1);
+  CHECK_HISTORY (p1, 3, 
+                 1, 10, 4);
+  p1.RemoveAtEnd (4);
+  CHECK_HISTORY (p1, 2, 
+                 1, 10);
+  p1.RemoveAtStart (1);
+  CHECK_HISTORY (p1, 1, 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);
+
+  p = Packet (10);
+  ADD_HEADER (p, 10);
+  ADD_HEADER (p, 8);
+  ADD_TRAILER (p, 6);
+  ADD_TRAILER (p, 7);
+  ADD_TRAILER (p, 9);
+  p.RemoveAtStart (5);
+  p.RemoveAtEnd (12);
+  CHECK_HISTORY (p, 5, 3, 10, 10, 6, 4);
+
+  p = Packet (10);
+  ADD_HEADER (p, 10);
+  ADD_TRAILER (p, 6);
+  p.RemoveAtEnd (18);
+  ADD_TRAILER (p, 5);
+  ADD_HEADER (p, 3);
+  CHECK_HISTORY (p, 3, 3, 8, 5);
+  p.RemoveAtStart (12);
+  CHECK_HISTORY (p, 1, 4);
+  p.RemoveAtEnd (2);
+  CHECK_HISTORY (p, 1, 2);
+  ADD_HEADER (p, 10);
+  CHECK_HISTORY (p, 2, 10, 2);
+  p.RemoveAtEnd (5);
+  CHECK_HISTORY (p, 1, 7);
+
+  Packet p2 = Packet (0);
+  Packet p3 = Packet (0);
+
+  p = Packet (40);
+  ADD_HEADER (p, 5);
+  ADD_HEADER (p, 8);
+  CHECK_HISTORY (p, 3, 8, 5, 40);
+  p1 = p.CreateFragment (0, 5);
+  p2 = p.CreateFragment (5, 5);
+  p3 = p.CreateFragment (10, 43);
+  CHECK_HISTORY (p1, 1, 5);
+  CHECK_HISTORY (p2, 2, 3, 2);
+  CHECK_HISTORY (p3, 2, 3, 40);
+  p1.AddAtEnd (p2);
+  CHECK_HISTORY (p1, 2, 8, 2);
+  CHECK_HISTORY (p2, 2, 3, 2);
+  p1.AddAtEnd (p3);
+  CHECK_HISTORY (p1, 3, 8, 5, 40);
+  CHECK_HISTORY (p2, 2, 3, 2);
+  CHECK_HISTORY (p3, 2, 3, 40);
+  p1 = p.CreateFragment (0, 5);
+  CHECK_HISTORY (p1, 1, 5);
+
+  p3 = Packet (50);
+  ADD_HEADER (p3, 8);
+  CHECK_HISTORY (p3, 2, 8, 50);
+  CHECK_HISTORY (p1, 1, 5);
+  p1.AddAtEnd (p3);
+  CHECK_HISTORY (p1, 3, 5, 8, 50);
+  ADD_HEADER (p1, 5);
+  CHECK_HISTORY (p1, 4, 5, 5, 8, 50);
+  ADD_TRAILER (p1, 2);
+  CHECK_HISTORY (p1, 5, 5, 5, 8, 50, 2);
+  REM_HEADER (p1, 5);
+  CHECK_HISTORY (p1, 4, 5, 8, 50, 2);
+  p1.RemoveAtEnd (60);
+  CHECK_HISTORY (p1, 1, 5);
+  p1.AddAtEnd (p2);
+  CHECK_HISTORY (p1, 2, 8, 2);
+  CHECK_HISTORY (p2, 2, 3, 2);
+
+  p3 = Packet (40);
+  ADD_HEADER (p3, 5);
+  ADD_HEADER (p3, 5);
+  CHECK_HISTORY (p3, 3, 5, 5, 40);
+  p1 = p3.CreateFragment (0, 5);
+  p2 = p3.CreateFragment (5, 5);
+  CHECK_HISTORY (p1, 1, 5);
+  CHECK_HISTORY (p2, 1, 5);
+  p1.AddAtEnd (p2);
+  CHECK_HISTORY (p1, 2, 5, 5);
+
+  p = Packet (0);
+  CHECK_HISTORY (p, 0);
+
+  p3 = Packet (0);
+  ADD_HEADER (p3, 5);
+  ADD_HEADER (p3, 5);
+  CHECK_HISTORY (p3, 2, 5, 5);
+  p1 = p3.CreateFragment (0, 4);
+  p2 = p3.CreateFragment (9, 1);
+  CHECK_HISTORY (p1, 1, 4);
+  CHECK_HISTORY (p2, 1, 1);
+  p1.AddAtEnd (p2);
+  CHECK_HISTORY (p1, 2, 4, 1);
+
+
+  p = Packet (2000);
+  CHECK_HISTORY (p, 1, 2000);
+  
+  p = Packet ();
+  ADD_TRAILER (p, 10);
+  ADD_HEADER (p, 5);
+  p1 = p.CreateFragment (0, 8);
+  p2 = p.CreateFragment (8, 7);
+  p1.AddAtEnd (p2);
+  CHECK_HISTORY (p, 2, 5, 10);
+
+  p = Packet ();
+  ADD_TRAILER (p, 10);
+  REM_TRAILER (p, 10);
+  ADD_TRAILER (p, 10);
+  CHECK_HISTORY (p, 1, 10);
+
+  p = Packet ();
+  ADD_HEADER (p, 10);
+  REM_HEADER (p, 10);
+  ADD_HEADER (p, 10);
+  CHECK_HISTORY (p, 1, 10);
+
+  p = Packet ();
+  ADD_HEADER (p, 10);
+  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;
+}
+
+static PacketMetadataTest g_packetHistoryTest;
+
+}//namespace ns3
+
+#endif /* RUN_SELF_TESTS */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/packet-metadata.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,1250 @@
+/* -*- 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 <utility>
+#include <list>
+#include "ns3/assert.h"
+#include "ns3/fatal-error.h"
+#include "ns3/log.h"
+#include "packet-metadata.h"
+#include "buffer.h"
+#include "chunk-registry.h"
+
+NS_LOG_COMPONENT_DEFINE ("PacketMetadata");
+
+namespace ns3 {
+
+bool PacketMetadata::m_enable = false;
+bool PacketMetadata::m_metadataSkipped = false;
+uint32_t PacketMetadata::m_maxSize = 0;
+uint16_t PacketMetadata::m_chunkUid = 0;
+PacketMetadata::DataFreeList PacketMetadata::m_freeList;
+bool g_optOne = false;
+
+PacketMetadata::DataFreeList::~DataFreeList ()
+{
+  for (iterator i = begin (); i != end (); i++)
+    {
+      PacketMetadata::Deallocate (*i);
+    }
+}
+
+void 
+PacketMetadata::Enable (void)
+{
+  NS_ASSERT_MSG (!m_metadataSkipped,
+                 "Error: attempting to enable the packet metadata "
+                 "subsystem too late in the simulation, which is not allowed.\n"
+                 "A common cause for this problem is to enable ASCII tracing "
+                 "after sending any packets.  One way to fix this problem is "
+                 "to call ns3::PacketMetadata::Enable () near the beginning of"
+                 " the program, before any packets are sent.");
+  m_enable = true;
+}
+
+void 
+PacketMetadata::SetOptOne (bool optOne)
+{
+  g_optOne = optOne;
+}
+
+void
+PacketMetadata::ReserveCopy (uint32_t size)
+{
+  struct PacketMetadata::Data *newData = PacketMetadata::Create (m_used + size);
+  memcpy (newData->m_data, m_data->m_data, m_used);
+  newData->m_dirtyEnd = m_used;
+  m_data->m_count--;
+  if (m_data->m_count == 0) 
+    {
+      PacketMetadata::Recycle (m_data);
+    }
+  m_data = newData;
+  if (m_head != 0xffff)
+    {
+      uint8_t *start;
+      NS_ASSERT (m_tail != 0xffff);
+      // clear the next field of the tail
+      start = &m_data->m_data[m_tail];
+      Append16 (0xffff, start);
+      // clear the prev field of the head
+      start = &m_data->m_data[m_head] + 2;
+      Append16 (0xffff, start);
+    }
+}
+void
+PacketMetadata::Reserve (uint32_t size)
+{
+  NS_ASSERT (m_data != 0);
+  if (m_data->m_size >= m_used + size &&
+      (m_head == 0xffff ||
+       m_data->m_count == 1 ||
+       m_data->m_dirtyEnd == m_used))
+    {
+      /* enough room, not dirty. */
+    }
+  else 
+    {
+      /* (enough room and dirty) or (not enough room) */
+      ReserveCopy (size);
+    }
+}
+
+uint32_t 
+PacketMetadata::GetUleb128Size (uint32_t value) const
+{
+  if (value < 0x80)
+    {
+      return 1;
+    }
+  if (value < 0x4000)
+    {
+      return 2;
+    }
+  if (value < 0x200000)
+    {
+      return 3;
+    }
+  if (value < 0x10000000)
+    {
+      return 4;
+    }
+  return 5;
+}
+uint32_t
+PacketMetadata::ReadUleb128 (const uint8_t **pBuffer) const
+{
+  const uint8_t *buffer = *pBuffer;
+  uint32_t result = 0;
+  uint8_t byte;
+  result = 0;
+  byte = buffer[0];
+  result = (byte & (~0x80));
+  if (!(byte & 0x80))
+    {
+      *pBuffer = buffer + 1;
+      return result;
+    }
+  byte = buffer[1];
+  result |= (byte & (~0x80)) << 7;
+  if (!(byte & 0x80))
+    {
+      *pBuffer = buffer + 2;
+      return result;
+    }
+  byte = buffer[2];
+  result |= (byte & (~0x80)) << 14;
+  if (!(byte & 0x80))
+    {
+      *pBuffer = buffer + 3;
+      return result;
+    }
+  byte = buffer[3];
+  result |= (byte & (~0x80)) << 21;
+  if (!(byte & 0x80))
+    {
+      *pBuffer = buffer + 4;
+      return result;
+    }
+  byte = buffer[4];
+  result |= (byte & (~0x80)) << 28;
+  if (!(byte & 0x80))
+    {
+      *pBuffer = buffer + 5;
+      return result;
+    }
+  /* This means that the LEB128 number was not valid.
+   * ie: the last (5th) byte did not have the high-order bit zeroed.
+   */
+  NS_ASSERT (false);
+  return 0;
+}
+
+void
+PacketMetadata::Append16 (uint16_t value, uint8_t *buffer)
+{
+  buffer[0] = value & 0xff;
+  value >>= 8;
+  buffer[1] = value;
+}
+bool
+PacketMetadata::TryToAppendFast (uint32_t value, uint8_t **pBuffer, uint8_t *end)
+{
+  uint8_t *start = *pBuffer;
+  if (value < 0x80 && start < end)
+    {
+      start[0] = value;
+      *pBuffer = start + 1;
+      return true;
+    }
+  if (value < 0x4000 && start + 1 < end)
+    {
+      uint8_t byte = value & (~0x80);
+      start[0] = 0x80 | byte;
+      value >>= 7;
+      start[1] = value;
+      *pBuffer = start + 2;
+      return true;
+    }
+  return false;
+}
+bool
+PacketMetadata::TryToAppend16 (uint16_t value,  uint8_t **pBuffer, uint8_t *end)
+{
+  uint8_t *start = *pBuffer;
+  if (start + 1 < end)
+    {
+      start[0] = value & 0xff;
+      start[1] = value >> 8;
+      *pBuffer = start + 2;
+      return true;
+    }
+  return false;
+}
+bool
+PacketMetadata::TryToAppend32 (uint32_t value,  uint8_t **pBuffer, uint8_t *end)
+{
+  uint8_t *start = *pBuffer;
+  if (start + 3 < end)
+    {
+      start[0] = value & 0xff;
+      start[1] = (value >> 8) & 0xff;
+      start[2] = (value >> 16) & 0xff;
+      start[3] = (value >> 24) & 0xff;
+      *pBuffer = start + 4;
+      return true;
+    }
+  return false;
+}
+bool
+PacketMetadata::TryToAppend (uint32_t value, uint8_t **pBuffer, uint8_t *end)
+{
+  uint8_t *start = *pBuffer;
+  if (value < 0x80 && start < end)
+    {
+      start[0] = value;
+      *pBuffer = start + 1;
+      return true;
+    }
+  if (value < 0x4000 && start + 1 < end)
+    {
+      uint8_t byte = value & (~0x80);
+      start[0] = 0x80 | byte;
+      value >>= 7;
+      start[1] = value;
+      *pBuffer = start + 2;
+      return true;
+    }
+  if (value < 0x200000 && start + 2 < end)
+    {
+      uint8_t byte = value & (~0x80);
+      start[0] = 0x80 | byte;
+      value >>= 7;
+      byte = value & (~0x80);
+      start[1] = 0x80 | byte;
+      value >>= 7;
+      byte = value & (~0x80);
+      start[2] = value;
+      *pBuffer = start + 3;
+      return true;
+    }
+  if (value < 0x10000000 && start + 3 < end)
+    {
+      uint8_t byte = value & (~0x80);
+      start[0] = 0x80 | byte;
+      value >>= 7;
+      byte = value & (~0x80);
+      start[1] = 0x80 | byte;
+      value >>= 7;
+      byte = value & (~0x80);
+      start[2] = 0x80 | byte;
+      value >>= 7;
+      start[3] = value;
+      *pBuffer = start + 4;
+      return true;
+    }
+  if (start + 4 < end)
+    {
+      uint8_t byte = value & (~0x80);
+      start[0] = 0x80 | byte;
+      value >>= 7;
+      byte = value & (~0x80);
+      start[1] = 0x80 | byte;
+      value >>= 7;
+      byte = value & (~0x80);
+      start[2] = 0x80 | byte;
+      value >>= 7;
+      byte = value & (~0x80);
+      start[3] = 0x80 | byte;
+      value >>= 7;
+      start[4] = value;
+      *pBuffer = start + 5;
+      return true;
+    }
+  return false;
+}
+
+void
+PacketMetadata::AppendValueExtra (uint32_t value, uint8_t *buffer)
+{
+  if (value < 0x200000)
+    {
+      uint8_t byte = value & (~0x80);
+      buffer[0] = 0x80 | byte;
+      value >>= 7;
+      byte = value & (~0x80);
+      buffer[1] = 0x80 | byte;
+      value >>= 7;
+      byte = value & (~0x80);
+      buffer[2] = value;
+      return;
+    }
+  if (value < 0x10000000)
+    {
+      uint8_t byte = value & (~0x80);
+      buffer[0] = 0x80 | byte;
+      value >>= 7;
+      byte = value & (~0x80);
+      buffer[1] = 0x80 | byte;
+      value >>= 7;
+      byte = value & (~0x80);
+      buffer[2] = 0x80 | byte;
+      value >>= 7;
+      buffer[3] = value;
+      return;
+    }
+  {
+    uint8_t byte = value & (~0x80);
+    buffer[0] = 0x80 | byte;
+    value >>= 7;
+    byte = value & (~0x80);
+    buffer[1] = 0x80 | byte;
+    value >>= 7;
+    byte = value & (~0x80);
+    buffer[2] = 0x80 | byte;
+    value >>= 7;
+    byte = value & (~0x80);
+    buffer[3] = 0x80 | byte;
+    value >>= 7;
+    buffer[4] = value;
+  }
+}
+
+void
+PacketMetadata::AppendValue (uint32_t value, uint8_t *buffer)
+{
+  if (value < 0x80)
+    {
+      buffer[0] = value;
+      return;
+    }
+  if (value < 0x4000)
+    {
+      uint8_t byte = value & (~0x80);
+      buffer[0] = 0x80 | byte;
+      value >>= 7;
+      buffer[1] = value;
+      return;
+    }
+  AppendValueExtra (value, buffer);
+}
+
+void
+PacketMetadata::UpdateTail (uint16_t written)
+{
+  if (m_head == 0xffff)
+    {
+      NS_ASSERT (m_tail == 0xffff);
+      m_head = m_used;
+      m_tail = m_used;
+    } 
+  else
+    {
+      NS_ASSERT (m_tail != 0xffff);
+      // overwrite the next field of the previous tail of the list.
+      uint8_t *previousTail = &m_data->m_data[m_tail];
+      Append16 (m_used, previousTail);
+      // update the tail of the list to the new node.
+      m_tail = m_used;
+    }
+  NS_ASSERT (m_tail != 0xffff);
+  NS_ASSERT (m_head != 0xffff);
+  NS_ASSERT (written >= 8);
+  m_used += written;
+  m_data->m_dirtyEnd = m_used;
+}
+
+
+void
+PacketMetadata::UpdateHead (uint16_t written)
+{
+  if (m_head == 0xffff)
+    {
+      NS_ASSERT (m_tail == 0xffff);
+      m_head = m_used;
+      m_tail = m_used;
+    } 
+  else
+    {
+      NS_ASSERT (m_head != 0xffff);
+      // overwrite the prev field of the previous head of the list.
+      uint8_t *previousHead = &m_data->m_data[m_head + 2];
+      Append16 (m_used, previousHead);
+      // update the head of list to the new node.
+      m_head = m_used;
+    }
+  NS_ASSERT (m_tail != 0xffff);
+  NS_ASSERT (m_head != 0xffff);
+  NS_ASSERT (written >= 8);
+  m_used += written;
+  m_data->m_dirtyEnd = m_used;
+}
+
+uint16_t
+PacketMetadata::AddSmall (const struct PacketMetadata::SmallItem *item)
+{
+  NS_ASSERT (m_data != 0);
+  NS_ASSERT (m_used != item->prev && m_used != item->next);
+  if (g_optOne)
+    {
+      uint32_t typeUidSize = GetUleb128Size (item->typeUid);
+      uint32_t sizeSize = GetUleb128Size (item->size);
+      uint32_t n = typeUidSize + sizeSize + 2 + 2 + 2;
+    restart:
+      if (m_used + n <= m_data->m_size &&
+      (m_head == 0xffff ||
+       m_data->m_count == 1 ||
+       m_used == m_data->m_dirtyEnd))
+        {
+          uint8_t *buffer = &m_data->m_data[m_used];
+          Append16 (item->next, buffer);
+          buffer += 2;
+          Append16 (item->prev, buffer);
+          buffer += 2;
+          AppendValue (item->typeUid, buffer);
+          buffer += typeUidSize;
+          AppendValue (item->size, buffer);
+          buffer += sizeSize;
+          Append16 (item->chunkUid, buffer);
+        }
+      else
+        {
+          ReserveCopy (n);
+          goto restart;
+        }
+      return n;
+    }
+ append:
+  uint8_t *start = &m_data->m_data[m_used];
+  uint8_t *end = &m_data->m_data[m_data->m_size];
+  if (end - start >= 8 &&
+      (m_head == 0xffff ||
+       m_data->m_count == 1 ||
+       m_used == m_data->m_dirtyEnd))
+    {
+      uint8_t *buffer = start;
+
+      Append16 (item->next, buffer);
+      buffer += 2;
+      Append16 (item->prev, buffer);
+      buffer += 2;
+      if (TryToAppendFast (item->typeUid, &buffer, end) &&
+          TryToAppendFast (item->size, &buffer, end) &&
+          TryToAppend16 (item->chunkUid, &buffer, end))
+        {
+          uintptr_t written = buffer - start;
+          NS_ASSERT (written <= 0xffff);
+          NS_ASSERT (written >= 8);
+          return written;
+        }
+    }
+  uint32_t n = GetUleb128Size (item->typeUid);
+  n += GetUleb128Size (item->size);
+  n += 2;
+  n += 2 + 2;
+  Reserve (n);
+  goto append;
+}
+
+uint16_t
+PacketMetadata::AddBig (uint32_t next, uint32_t prev, 
+                       const PacketMetadata::SmallItem *item, 
+                       const PacketMetadata::ExtraItem *extraItem)
+{
+  NS_ASSERT (m_data != 0);
+  uint32_t typeUid = ((item->typeUid & 0x1) == 0x1)?item->typeUid:item->typeUid+1;
+  NS_ASSERT (m_used != prev && m_used != next);
+ append:
+  uint8_t *start = &m_data->m_data[m_used];
+  uint8_t *end = &m_data->m_data[m_data->m_size];
+  if (end - start >= 14 &&
+      (m_head == 0xffff ||
+       m_data->m_count == 1 ||
+       m_used == m_data->m_dirtyEnd))
+    {
+      uint8_t *buffer = start;
+
+      Append16 (next, buffer);
+      buffer += 2;
+      Append16 (prev, buffer);
+      buffer += 2;
+      if (TryToAppend (typeUid, &buffer, end) &&
+          TryToAppend (item->size, &buffer, end) &&
+          TryToAppend16 (item->chunkUid, &buffer, end) &&
+          TryToAppend (extraItem->fragmentStart, &buffer, end) &&
+          TryToAppend (extraItem->fragmentEnd, &buffer, end) &&
+          TryToAppend32 (extraItem->packetUid, &buffer, end))
+        {
+          uintptr_t written = buffer - start;
+          NS_ASSERT (written <= 0xffff);
+          NS_ASSERT (written >= 14);
+          return written;
+        }
+    }
+
+  uint32_t n = GetUleb128Size (typeUid);
+  n += GetUleb128Size (item->size);
+  n += 2;
+  n += GetUleb128Size (extraItem->fragmentStart);
+  n += GetUleb128Size (extraItem->fragmentEnd);
+  n += 4;
+  n += 2 + 2;
+  ReserveCopy (n);
+  goto append;
+}
+
+void
+PacketMetadata::ReplaceTail (PacketMetadata::SmallItem *item, 
+                            PacketMetadata::ExtraItem *extraItem,
+                            uint32_t available)
+{
+  NS_ASSERT (m_data != 0);  
+  if (available >= 14 &&
+      m_data->m_count == 1)
+    {
+      uint8_t *buffer = &m_data->m_data[m_tail];
+      uint8_t *end = buffer + available;
+
+      Append16 (item->next, buffer);
+      buffer += 2;
+      Append16 (item->prev, buffer);
+      buffer += 2;
+      if (TryToAppend (item->typeUid, &buffer, end) &&
+          TryToAppend (item->size, &buffer, end) &&
+          TryToAppend16 (item->chunkUid, &buffer, end) &&
+          TryToAppend (extraItem->fragmentStart, &buffer, end) &&
+          TryToAppend (extraItem->fragmentEnd, &buffer, end) &&
+          TryToAppend32 (extraItem->packetUid, &buffer, end))
+        {
+          m_used = buffer - &m_data->m_data[0];
+          m_data->m_dirtyEnd = m_used;
+          return;
+        }
+    }
+  
+  // create a copy of the packet.
+  PacketMetadata h (m_packetUid, 0);
+  uint16_t current = m_head;
+  while (current != 0xffff && current != m_tail)
+    {
+      struct PacketMetadata::SmallItem tmpItem;
+      PacketMetadata::ExtraItem tmpExtraItem;
+      ReadItems (current, &tmpItem, &tmpExtraItem);
+      uint16_t written = h.AddBig (0xffff, h.m_tail, 
+                                   &tmpItem, &tmpExtraItem);
+      h.UpdateTail (written);
+    }
+  // append new tail.
+  uint16_t written = h.AddBig (0xffff, h.m_tail, item, extraItem);
+  h.UpdateTail (written);
+
+  *this = h;
+}
+
+uint32_t
+PacketMetadata::ReadItems (uint16_t current, 
+                          struct PacketMetadata::SmallItem *item,
+                          struct PacketMetadata::ExtraItem *extraItem) const
+{
+  const uint8_t *buffer = &m_data->m_data[current];
+  item->next = buffer[0];
+  item->next |= (buffer[1]) << 8;
+  item->prev = buffer[2];
+  item->prev |= (buffer[3]) << 8;
+  buffer += 4;
+  item->typeUid = ReadUleb128 (&buffer);
+  item->size = ReadUleb128 (&buffer);
+  item->chunkUid = buffer[0];
+  item->chunkUid |= (buffer[1]) << 8;
+  buffer += 2;
+
+  bool isExtra = (item->typeUid & 0x1) == 0x1;
+  if (isExtra)
+    {
+      extraItem->fragmentStart = ReadUleb128 (&buffer);
+      extraItem->fragmentEnd = ReadUleb128 (&buffer);
+      extraItem->packetUid = buffer[0];
+      extraItem->packetUid |= buffer[1] << 8;
+      extraItem->packetUid |= buffer[2] << 16;
+      extraItem->packetUid |= buffer[3] << 24;
+      buffer += 4;
+    }
+  else
+    {
+      extraItem->fragmentStart = 0;
+      extraItem->fragmentEnd = item->size;
+      extraItem->packetUid = m_packetUid;
+    }
+  NS_ASSERT (buffer <= &m_data->m_data[m_data->m_size]);
+  return buffer - &m_data->m_data[current];
+}
+
+struct PacketMetadata::Data *
+PacketMetadata::Create (uint32_t size)
+{
+  NS_LOG_LOGIC ("create size="<<size<<", max="<<m_maxSize);
+  if (size > m_maxSize)
+    {
+      m_maxSize = size;
+    }
+  while (!m_freeList.empty ()) 
+    {
+      struct PacketMetadata::Data *data = m_freeList.back ();
+      m_freeList.pop_back ();
+      if (data->m_size >= size) 
+        {
+          NS_LOG_LOGIC ("create found size="<<data->m_size);
+          data->m_count = 1;
+          return data;
+        }
+      PacketMetadata::Deallocate (data);
+      NS_LOG_LOGIC ("create dealloc size="<<data->m_size);
+    }
+  NS_LOG_LOGIC ("create alloc size="<<m_maxSize);
+  return PacketMetadata::Allocate (m_maxSize);
+}
+
+void
+PacketMetadata::Recycle (struct PacketMetadata::Data *data)
+{
+  NS_LOG_LOGIC ("recycle size="<<data->m_size<<", list="<<m_freeList.size ());
+  NS_ASSERT (data->m_count == 0);
+  if (m_freeList.size () > 1000 ||
+      data->m_size < m_maxSize) 
+    {
+      PacketMetadata::Deallocate (data);
+    } 
+  else 
+    {
+      m_freeList.push_back (data);
+    }
+}
+
+struct PacketMetadata::Data *
+PacketMetadata::Allocate (uint32_t n)
+{
+  uint32_t size = sizeof (struct Data);
+  if (n <= 10)
+    {
+      n = 10;
+    }
+  size += n - 10;
+  uint8_t *buf = new uint8_t [size];
+  struct PacketMetadata::Data *data = (struct PacketMetadata::Data *)buf;
+  data->m_size = n;
+  data->m_count = 1;
+  data->m_dirtyEnd = 0;
+  return data;
+}
+void 
+PacketMetadata::Deallocate (struct PacketMetadata::Data *data)
+{
+  uint8_t *buf = (uint8_t *)data;
+  delete [] buf;
+}
+
+
+PacketMetadata 
+PacketMetadata::CreateFragment (uint32_t start, uint32_t end) const
+{
+  PacketMetadata fragment = *this;
+  fragment.RemoveAtStart (start);
+  fragment.RemoveAtEnd (end);
+  return fragment;
+}
+
+void 
+PacketMetadata::DoAddHeader (uint32_t uid, uint32_t size)
+{
+  if (!m_enable)
+    {
+      m_metadataSkipped = true;
+      return;
+    }
+  NS_LOG_PARAM ("(uid=" << uid << ", size=" << size << ")");
+
+  struct PacketMetadata::SmallItem item;
+  item.next = m_head;
+  item.prev = 0xffff;
+  item.typeUid = uid;
+  item.size = size;
+  item.chunkUid = m_chunkUid;
+  m_chunkUid++;
+  uint16_t written = AddSmall (&item);
+  UpdateHead (written);
+}
+void 
+PacketMetadata::DoRemoveHeader (uint32_t uid, uint32_t size)
+{
+  if (!m_enable) 
+    {
+      m_metadataSkipped = true;
+      return;
+    }
+  NS_LOG_PARAM ("(uid=" << uid << ", size=" << size << ")");
+  struct PacketMetadata::SmallItem item;
+  struct PacketMetadata::ExtraItem extraItem;
+  uint32_t read = ReadItems (m_head, &item, &extraItem);
+  if ((item.typeUid & 0xfffffffe) != uid ||
+      item.size != size)
+    {
+      NS_FATAL_ERROR ("Removing unexpected header.");
+    }
+  else if (item.typeUid != uid &&
+           (extraItem.fragmentStart != 0 ||
+            extraItem.fragmentEnd != size))
+    {
+      NS_FATAL_ERROR ("Removing incomplete header.");
+    }
+  if (m_head + read == m_used)
+    {
+      m_used = m_head;
+    }
+  if (item.next == 0xffff)
+    {
+      m_head = 0xffff;
+      m_tail = 0xffff;
+    }
+  else
+    {
+      m_head = item.next;
+    }
+}
+void 
+PacketMetadata::DoAddTrailer (uint32_t uid, uint32_t size)
+{
+  if (!m_enable)
+    {
+      m_metadataSkipped = true;
+      return;
+    }
+  struct PacketMetadata::SmallItem item;
+  item.next = 0xffff;
+  item.prev = m_tail;
+  item.typeUid = uid;
+  item.size = size;
+  item.chunkUid = m_chunkUid;
+  m_chunkUid++;
+  uint16_t written = AddSmall (&item);
+  UpdateTail (written);
+}
+void 
+PacketMetadata::DoRemoveTrailer (uint32_t uid, uint32_t size)
+{
+  if (!m_enable) 
+    {
+      m_metadataSkipped = true;
+      return;
+    }
+  struct PacketMetadata::SmallItem item;
+  struct PacketMetadata::ExtraItem extraItem;
+  uint32_t read = ReadItems (m_tail, &item, &extraItem);
+  if ((item.typeUid & 0xfffffffe) != uid ||
+      item.size != size)
+    {
+      NS_FATAL_ERROR ("Removing unexpected trailer.");
+    }
+  else if (item.typeUid != uid &&
+           (extraItem.fragmentStart != 0 ||
+            extraItem.fragmentEnd != size))
+    {
+      NS_FATAL_ERROR ("Removing incomplete trailer.");
+    }
+  if (m_tail + read == m_used)
+    {
+      m_used = m_tail;
+    }  
+  if (item.prev == 0xffff)
+    {
+      m_head = 0xffff;
+      m_tail = 0xffff;
+    }
+  else
+    {
+      m_tail = item.prev;
+    }
+}
+void
+PacketMetadata::AddAtEnd (PacketMetadata const&o)
+{
+  if (!m_enable) 
+    {
+      m_metadataSkipped = true;
+      return;
+    }
+  if (m_tail == 0xffff)
+    {
+      *this = o;
+      return;
+    }
+  NS_ASSERT (m_head != 0xffff && m_tail != 0xffff);
+
+  uint16_t lastTail;
+  lastTail = m_tail;
+  struct PacketMetadata::SmallItem lastItem;
+  PacketMetadata::ExtraItem lastExtraItem;
+  uint32_t lastTailSize = ReadItems (m_tail, &lastItem, &lastExtraItem);
+  if (m_tail + lastTailSize == m_used &&
+      m_used == m_data->m_dirtyEnd)
+    {
+      lastTailSize = m_data->m_size - m_tail;
+    }
+
+  uint16_t current = o.m_head;
+  while (current != 0xffff)
+    {
+      struct PacketMetadata::SmallItem item;
+      PacketMetadata::ExtraItem extraItem;
+      o.ReadItems (current, &item, &extraItem);
+      if (extraItem.packetUid == lastExtraItem.packetUid &&
+          item.typeUid == lastItem.typeUid &&
+          item.chunkUid == lastItem.chunkUid &&
+          item.size == lastItem.size &&
+          extraItem.fragmentStart == lastExtraItem.fragmentEnd)
+        {
+          // replace previous tail.
+          lastExtraItem.fragmentEnd = extraItem.fragmentEnd;
+          NS_ASSERT (m_tail == lastTail);
+          // XXX This call might be wrong. 
+          ReplaceTail (&lastItem, &lastExtraItem, lastTailSize);
+        }
+      else
+        {
+          // append the extra items.
+          uint16_t written = AddBig (0xffff, m_tail, &item, &extraItem);
+          UpdateTail (written);
+        }
+      if (current == o.m_tail)
+        {
+          break;
+        }
+      current = item.next;
+    }
+}
+void
+PacketMetadata::AddPaddingAtEnd (uint32_t end)
+{
+  if (!m_enable)
+    {
+      m_metadataSkipped = true;
+      return;
+    }
+}
+void 
+PacketMetadata::RemoveAtStart (uint32_t start)
+{
+  if (!m_enable) 
+    {
+      m_metadataSkipped = true;
+      return;
+    }
+  NS_ASSERT (m_data != 0);
+  uint32_t leftToRemove = start;
+  uint16_t current = m_head;
+  while (current != 0xffff && leftToRemove > 0)
+    {
+      struct PacketMetadata::SmallItem item;
+      PacketMetadata::ExtraItem extraItem;
+      ReadItems (current, &item, &extraItem);
+      uint32_t itemRealSize = extraItem.fragmentEnd - extraItem.fragmentStart;
+      if (itemRealSize <= leftToRemove)
+        {
+          // remove from list.
+          m_head = item.next;
+          leftToRemove -= itemRealSize;
+        }
+      else
+        {
+          // fragment the list item.
+          PacketMetadata fragment (m_packetUid, 0);
+          extraItem.fragmentStart += leftToRemove;
+          leftToRemove = 0;
+          uint16_t written = fragment.AddBig (0xffff, fragment.m_tail,
+                                              &item, &extraItem);
+          fragment.UpdateTail (written);
+          current = item.next;
+          while (current != 0xffff)
+            {
+              ReadItems (current, &item, &extraItem);
+              written = fragment.AddBig (0xffff, fragment.m_tail,
+                                         &item, &extraItem);
+              fragment.UpdateTail (written);
+              if (current == m_tail)
+                {
+                  break;
+                }
+              current = item.next;
+            }
+          *this = fragment;
+        }
+      NS_ASSERT (item.size >= extraItem.fragmentEnd - extraItem.fragmentStart &&
+                 extraItem.fragmentStart <= extraItem.fragmentEnd);
+      if (current == m_tail)
+        {
+          break;
+        }
+      current = item.next;
+    }
+  NS_ASSERT (leftToRemove == 0);
+}
+void 
+PacketMetadata::RemoveAtEnd (uint32_t end)
+{
+  if (!m_enable) 
+    {
+      m_metadataSkipped = true;
+      return;
+    }
+  NS_ASSERT (m_data != 0);
+
+  uint32_t leftToRemove = end;
+  uint16_t current = m_tail;
+  while (current != 0xffff && leftToRemove > 0)
+    {
+      struct PacketMetadata::SmallItem item;
+      PacketMetadata::ExtraItem extraItem;
+      ReadItems (current, &item, &extraItem);
+      uint32_t itemRealSize = extraItem.fragmentEnd - extraItem.fragmentStart;
+      if (itemRealSize <= leftToRemove)
+        {
+          // remove from list.
+          m_tail = item.prev;
+          leftToRemove -= itemRealSize;
+        }
+      else
+        {
+          // fragment the list item.
+          PacketMetadata fragment (m_packetUid, 0);
+          NS_ASSERT (extraItem.fragmentEnd > leftToRemove);
+          extraItem.fragmentEnd -= leftToRemove;
+          leftToRemove = 0;
+          uint16_t written = fragment.AddBig (fragment.m_head, 0xffff,
+                                              &item, &extraItem);
+          fragment.UpdateHead (written);
+          current = item.prev;
+          while (current != 0xffff)
+            {
+              ReadItems (current, &item, &extraItem);
+              written = fragment.AddBig (fragment.m_head, 0xffff,
+                                         &item, &extraItem);
+              fragment.UpdateHead (written);
+              if (current == m_head)
+                {
+                  break;
+                }
+              current = item.prev;
+            }
+          *this = fragment;
+        }
+      NS_ASSERT (item.size >= extraItem.fragmentEnd - extraItem.fragmentStart &&
+                 extraItem.fragmentStart <= extraItem.fragmentEnd);
+      if (current == m_head)
+        {
+          break;
+        }
+      current = item.prev;
+    }
+  NS_ASSERT (leftToRemove == 0);
+}
+
+uint32_t
+PacketMetadata::DoPrint (const struct PacketMetadata::SmallItem *item, 
+                         const struct PacketMetadata::ExtraItem *extraItem,
+                         Buffer data, uint32_t offset, const PacketPrinter &printer,
+                         std::ostream &os) const
+{
+  uint32_t uid = (item->typeUid & 0xfffffffe) >> 1;
+  if (uid == 0)
+    {
+      // payload.
+      printer.PrintPayload (os, extraItem->packetUid, item->size, 
+                            extraItem->fragmentStart, 
+                            item->size - extraItem->fragmentEnd);
+    }
+  else if (extraItem->fragmentStart != 0 ||
+           extraItem->fragmentEnd != item->size)
+    {
+      printer.PrintChunkFragment (uid, os, extraItem->packetUid, item->size, 
+                                  extraItem->fragmentStart, 
+                                  item->size - extraItem->fragmentEnd);
+    }
+  else if (ChunkRegistry::IsHeader (uid))
+    {
+      ns3::Buffer::Iterator j = data.Begin ();
+      j.Next (offset);
+      printer.PrintChunk (uid, j, os, extraItem->packetUid, item->size);
+    }
+  else if (ChunkRegistry::IsTrailer (uid))
+    {
+      ns3::Buffer::Iterator j = data.End ();
+      j.Prev (data.GetSize () - (offset + item->size));
+      printer.PrintChunk (uid, j, os, extraItem->packetUid, item->size);
+    }
+  else 
+    {
+      NS_ASSERT (false);
+    }
+  return extraItem->fragmentEnd - extraItem->fragmentStart;
+}
+
+uint32_t
+PacketMetadata::GetTotalSize (void) const
+{
+  uint32_t totalSize = 0;
+  uint16_t current = m_head;
+  uint16_t tail = m_tail;
+  while (current != 0xffff)
+    {
+      struct PacketMetadata::SmallItem item;
+      PacketMetadata::ExtraItem extraItem;
+      ReadItems (current, &item, &extraItem);
+      totalSize += extraItem.fragmentEnd - extraItem.fragmentStart;
+      if (current == tail)
+        {
+          break;
+        }
+      NS_ASSERT (current != item.next);
+      current = item.next;
+    }
+  return totalSize;
+}
+
+uint32_t 
+PacketMetadata::GetUid (void) const
+{
+  return m_packetUid;
+}
+
+void
+PacketMetadata::Print (std::ostream &os, Buffer data, const PacketPrinter &printer) const
+{
+  if (!m_enable) 
+    {
+      return;
+    }
+  NS_ASSERT (m_data != 0);
+  NS_ASSERT (GetTotalSize () == data.GetSize ());
+  struct PacketMetadata::SmallItem item;
+  struct PacketMetadata::ExtraItem extraItem;
+  if (printer.m_forward)
+    {
+      uint32_t current = m_head;
+      uint32_t offset = 0;
+      while (current != 0xffff)
+        {
+          ReadItems (current, &item, &extraItem);
+          uint32_t realSize = DoPrint (&item, &extraItem, data, offset, printer, os);
+          offset += realSize;
+          if (current == m_tail)
+            {
+              break;
+            }
+          if (item.next != 0xffff)
+            {
+              os << printer.m_separator;
+            }
+          NS_ASSERT (current != item.next);
+          current = item.next;
+        }
+    }
+  else
+    {
+      uint32_t current = m_tail;
+      uint32_t offset = data.GetSize ();
+      while (current != 0xffff)
+        {
+          ReadItems (current, &item, &extraItem);
+          uint32_t realSize = DoPrint (&item, &extraItem, data, offset - item.size, printer, os);
+          offset -= realSize;
+          if (current == m_head)
+            {
+              break;
+            }
+          if (item.prev != 0xffff)
+            {
+              os << printer.m_separator;
+            }
+          NS_ASSERT (current != item.prev);
+          current = item.prev;
+        }
+    }
+}
+
+uint32_t 
+PacketMetadata::GetSerializedSize (void) const
+{
+  uint32_t totalSize = 0;
+  totalSize += 4;
+  if (!m_enable)
+    {
+      return totalSize;
+    }
+  struct PacketMetadata::SmallItem item;
+  struct PacketMetadata::ExtraItem extraItem;
+  uint32_t current = m_head;
+  while (current != 0xffff)
+    {
+      ReadItems (current, &item, &extraItem);
+      uint32_t uid = (item.typeUid & 0xfffffffe) >> 1;
+      if (uid == 0)
+        {
+          totalSize += 4;
+        }
+      else
+        {
+          totalSize += 4 + ChunkRegistry::GetUidStringFromUid (uid).size ();
+        }
+      totalSize += 1 + 4 + 2 + 4 + 4 + 4;
+      if (current == m_tail)
+        {
+          break;
+        }
+      NS_ASSERT (current != item.next);
+      current = item.next;
+    }
+  return totalSize;
+}
+void 
+PacketMetadata::Serialize (Buffer::Iterator i, uint32_t size) const
+{
+  uint32_t bytesWritten = 0;
+  i.WriteU32 (size);
+  bytesWritten += 4;
+  struct PacketMetadata::SmallItem item;
+  struct PacketMetadata::ExtraItem extraItem;
+  uint32_t current = m_head;
+  while (current != 0xffff)
+    {
+      ReadItems (current, &item, &extraItem);
+      NS_LOG_LOGIC ("bytesWritten=" << bytesWritten << ", typeUid="<<
+        item.typeUid << ", size="<<item.size<<", chunkUid="<<item.chunkUid<<
+        ", fragmentStart="<<extraItem.fragmentStart<<", fragmentEnd="<<
+        extraItem.fragmentEnd<< ", packetUid="<<extraItem.packetUid);
+      uint32_t uid = (item.typeUid & 0xfffffffe) >> 1;
+      if (uid != 0)
+        {
+          std::string uidString = ChunkRegistry::GetUidStringFromUid (uid);
+          i.WriteU32 (uidString.size ());
+          bytesWritten += 4;
+          i.Write ((uint8_t *)uidString.c_str (), uidString.size ());
+          bytesWritten += uidString.size ();
+        }
+      else
+        {
+          i.WriteU32 (0);
+          bytesWritten += 4;
+        }
+      uint8_t isBig = item.typeUid & 0x1;
+      i.WriteU8 (isBig);
+      bytesWritten += 1;
+      i.WriteU32 (item.size);
+      bytesWritten += 4;
+      i.WriteU16 (item.chunkUid);
+      bytesWritten += 2;
+      i.WriteU32 (extraItem.fragmentStart);
+      bytesWritten += 4;
+      i.WriteU32 (extraItem.fragmentEnd);
+      bytesWritten += 4;
+      i.WriteU32 (extraItem.packetUid);
+      bytesWritten += 4;
+      if (current == m_tail)
+        {
+          break;
+        }
+      
+      NS_ASSERT (current != item.next);
+      current = item.next;
+    }
+  NS_ASSERT (bytesWritten == size);
+}
+uint32_t 
+PacketMetadata::Deserialize (Buffer::Iterator i)
+{
+  struct PacketMetadata::SmallItem item;
+  struct PacketMetadata::ExtraItem extraItem;
+  uint32_t totalSize = i.ReadU32 ();
+  uint32_t size = totalSize;
+  size -= 4;
+  while (size > 0)
+    {
+      uint32_t uidStringSize = i.ReadU32 ();
+      size -= 4;
+      uint32_t uid;
+      if (uidStringSize == 0)
+        {
+          // uid zero for payload.
+          uid = 0;
+        }
+      else
+        {
+          std::string uidString;
+          for (uint32_t j = 0; j < uidStringSize; j++)
+            {
+              uidString.push_back (i.ReadU8 ());
+              size --;
+            }
+          uid = ChunkRegistry::GetUidFromUidString (uidString);
+        }
+      uint8_t isBig = i.ReadU8 ();
+      size --;
+      item.typeUid = (uid << 1) | isBig;
+      item.size = i.ReadU32 ();
+      size -= 4;
+      item.chunkUid = i.ReadU16 ();
+      size -= 2;
+      extraItem.fragmentStart = i.ReadU32 ();
+      size -= 4;
+      extraItem.fragmentEnd = i.ReadU32 ();
+      size -= 4;
+      extraItem.packetUid = i.ReadU32 ();
+      size -= 4;
+      NS_LOG_LOGIC ("size=" << size << ", typeUid="<<item.typeUid <<
+        ", size="<<item.size<<", chunkUid="<<item.chunkUid<<
+        ", fragmentStart="<<extraItem.fragmentStart<<", fragmentEnd="<<
+        extraItem.fragmentEnd<< ", packetUid="<<extraItem.packetUid);
+      uint32_t tmp = AddBig (0xffff, m_tail, &item, &extraItem);
+      UpdateTail (tmp);
+    }
+  NS_ASSERT (size == 0);
+  return totalSize;
+}
+
+
+} // namespace ns3
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/packet-metadata.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,347 @@
+/* -*- 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
+ * 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 PACKET_METADATA_H
+#define PACKET_METADATA_H
+
+#include <stdint.h>
+#include <vector>
+#include "ns3/callback.h"
+#include "ns3/assert.h"
+#include "packet-printer.h"
+
+namespace ns3 {
+
+class Chunk;
+class Buffer;
+
+/**
+ * \internal
+ * \brief handle packet metadata about packet headers and trailers
+ *
+ * This class is used by the Packet class to record every operation
+ * performed on the packet's buffer. This class also provides
+ * an implementation of the Packet::Print methods which uses
+ * the metadata to analyse the content of the packet's buffer.
+ *
+ * To achieve this, this class maintains a linked list of so-called
+ * "items", each of which represents a header or a trailer, or 
+ * payload, or a fragment of any of these. Each item contains a "next"
+ * and a "prev" field which point to the next and previous entries
+ * in the linked list. The PacketMetadata class maintains a pair
+ * of pointers to the head and the tail of the linked list.
+ *
+ * Each entry in the list also maintains:
+ *   - its native size (the size it had when it was first added
+ *     to the packet)
+ *   - its type: identifies what kind of header, what kind of trailer,
+ *     if it is payload or not
+ *   - the uid of the packet to which it was first added
+ *   - the start and end of the area represented by a fragment
+ *     if it is one.
+ *
+ * This linked list is flattened in a byte buffer stored in
+ * struct PacketMetadata::Data. Each entry of the linked list is
+ * identified by an offset which identifies the first byte of the
+ * entry from the start of the data buffer. The size of this data
+ * buffer is 2^16-1 bytes maximum which somewhat limits the number
+ * of entries which can be stored in this linked list but it is
+ * quite unlikely to hit this limit in practice.
+ *
+ * Each item of the linked list is a variable-sized byte buffer
+ * made of a number of fields. Some of these fields are stored
+ * as fixed-size 32 bit integers, others as fixed-size 16 bit 
+ * integers, and some others as variable-size 32-bit integers.
+ * The variable-size 32 bit integers are stored using the uleb128
+ * encoding.
+ */
+class PacketMetadata {
+public:
+  static void Enable (void);
+  static void SetOptOne (bool optOne);
+
+  inline PacketMetadata (uint32_t uid, uint32_t size);
+  inline PacketMetadata (PacketMetadata const &o);
+  inline PacketMetadata &operator = (PacketMetadata const& o);
+  inline ~PacketMetadata ();
+
+  template <typename T>
+  void AddHeader (T const &header, uint32_t size);
+  template <typename T>
+  void RemoveHeader (T const &header, uint32_t size);
+
+  template <typename T>
+  void AddTrailer (T const &trailer, uint32_t size);
+  template <typename T>
+  void RemoveTrailer (T const &trailer, uint32_t size);
+
+  PacketMetadata CreateFragment (uint32_t start, uint32_t end) const;
+  void AddAtEnd (PacketMetadata const&o);
+  void AddPaddingAtEnd (uint32_t end);
+  void RemoveAtStart (uint32_t start);
+  void RemoveAtEnd (uint32_t end);
+
+  uint32_t GetUid (void) const;
+
+  void Print (std::ostream &os, Buffer buffer, PacketPrinter const &printer) const;
+
+  uint32_t GetSerializedSize (void) const;
+  void Serialize (Buffer::Iterator i, uint32_t size) const;
+  uint32_t Deserialize (Buffer::Iterator i);
+
+  static void PrintStats (void);
+
+private:
+  struct Data {
+    /* number of references to this struct Data instance. */
+    uint16_t m_count;
+    /* size (in bytes) of m_data buffer below */
+    uint16_t m_size;
+    /* max of the m_used field over all objects which 
+     * reference this struct Data instance */
+    uint16_t m_dirtyEnd;
+    /* variable-sized buffer of bytes */
+    uint8_t m_data[10];
+  };
+  /* Note that since the next and prev fields are 16 bit integers
+     and since the value 0xffff is reserved to identify the 
+     fact that the end or the start of the list is reached,
+     only a limited number of elements can be stored in 
+     a m_data byte buffer.
+   */
+  struct SmallItem {
+    /* offset (in bytes) from start of m_data buffer 
+       to next element in linked list. value is 0xffff 
+       if next element does not exist.
+       stored as a fixed-size 16 bit integer.
+    */
+    uint16_t next;
+    /* offset (in bytes) from start of m_data buffer 
+       to previous element in linked list. value is 0xffff 
+       if previous element does not exist.
+       stored as a fixed-size 16 bit integer.
+     */
+    uint16_t prev;
+    /* the high 31 bits of this field identify the 
+       type of the header or trailer represented by 
+       this item: the value zero represents payload.
+       If the low bit of this uid is one, an ExtraItem
+       structure follows this SmallItem structure.
+       stored as a variable-size 32 bit integer.
+     */
+    uint32_t typeUid;
+    /* the size (in bytes) of the header or trailer represented
+       by this element.
+       stored as a variable-size 32 bit integer.
+     */
+    uint32_t size;
+    /* this field tries to uniquely identify each header or 
+       trailer _instance_ while the typeUid field uniquely
+       identifies each header or trailer _type_. This field
+       is used to test whether two items are equal in the sense 
+       that they represent the same header or trailer instance.
+       That equality test is based on the typeUid and chunkUid
+       fields so, the likelyhood that two header instances 
+       share the same chunkUid _and_ typeUid is very small 
+       unless they are really representations of the same header
+       instance.
+       stored as a fixed-size 16 bit integer.
+     */
+    uint16_t chunkUid;
+  };
+  struct ExtraItem {
+    /* offset (in bytes) from start of original header to 
+       the start of the fragment still present.
+       stored as a variable-size 32 bit integer.
+     */
+    uint32_t fragmentStart;
+    /* offset (in bytes) from start of original header to 
+       the end of the fragment still present.
+       stored as a variable-size 32 bit integer.
+     */
+    uint32_t fragmentEnd;
+    /* the packetUid of the packet in which this header or trailer
+       was first added. It could be different from the m_packetUid
+       field if the user has aggregated multiple packets into one.
+       stored as a fixed-size 32 bit integer.
+     */
+    uint32_t packetUid;
+  };
+
+  class DataFreeList : public std::vector<struct Data *>
+  {
+  public:
+    ~DataFreeList ();
+  };
+  
+  PacketMetadata ();
+  void DoAddHeader (uint32_t uid, uint32_t size);
+  void DoRemoveHeader (uint32_t uid, uint32_t size);
+  void DoAddTrailer (uint32_t uid, uint32_t size);
+  void DoRemoveTrailer (uint32_t uid, uint32_t size);
+
+  inline uint16_t AddSmall (const PacketMetadata::SmallItem *item);
+  uint16_t AddBig (uint32_t head, uint32_t tail,
+                   const PacketMetadata::SmallItem *item, 
+                   const PacketMetadata::ExtraItem *extraItem);
+  void ReplaceTail (PacketMetadata::SmallItem *item, 
+                    PacketMetadata::ExtraItem *extraItem,
+                    uint32_t available);
+  inline void UpdateHead (uint16_t written);
+  inline void UpdateTail (uint16_t written);
+  uint32_t GetUleb128Size (uint32_t value) const;
+  uint32_t ReadUleb128 (const uint8_t **pBuffer) const;
+  inline void Append16 (uint16_t value, uint8_t *buffer);
+  inline bool TryToAppend (uint32_t value, uint8_t **pBuffer, uint8_t *end);
+  inline bool TryToAppendFast (uint32_t value, uint8_t **pBuffer, uint8_t *end);
+  inline bool TryToAppend32 (uint32_t value, uint8_t **pBuffer, uint8_t *end);
+  inline bool TryToAppend16 (uint16_t value, uint8_t **pBuffer, uint8_t *end);
+  void AppendValue (uint32_t value, uint8_t *buffer);
+  void AppendValueExtra (uint32_t value, uint8_t *buffer);
+  inline void Reserve (uint32_t n);
+  void ReserveCopy (uint32_t n);
+  uint32_t DoPrint (const struct PacketMetadata::SmallItem *item,
+                    const struct PacketMetadata::ExtraItem *extraItem,
+                    Buffer data, uint32_t offset, const PacketPrinter &printer,
+                    std::ostream &os) const;
+  uint32_t GetTotalSize (void) const;
+  uint32_t ReadItems (uint16_t current, 
+                      struct PacketMetadata::SmallItem *item,
+                      struct PacketMetadata::ExtraItem *extraItem) const;
+
+
+  static struct PacketMetadata::Data *Create (uint32_t size);
+  static void Recycle (struct PacketMetadata::Data *data);
+  static struct PacketMetadata::Data *Allocate (uint32_t n);
+  static void Deallocate (struct PacketMetadata::Data *data);
+  
+  static DataFreeList m_freeList;
+  static bool m_enable;
+
+  // set to true when adding metadata to a packet is skipped because
+  // m_enable is false; used to detect enabling of metadata in the
+  // middle of a simulation, which isn't allowed.
+  static bool m_metadataSkipped;
+
+  static uint32_t m_maxSize;
+  static uint16_t m_chunkUid;
+  
+  struct Data *m_data;
+  /**
+     head -(next)-> tail
+       ^             |
+        \---(prev)---|
+   */
+  uint16_t m_head;
+  uint16_t m_tail;
+  uint16_t m_used;
+  uint32_t m_packetUid;
+};
+
+}; // namespace ns3
+
+namespace ns3 {
+
+template <typename T>
+void 
+PacketMetadata::AddHeader (T const &header, uint32_t size)
+{
+  DoAddHeader (T::GetUid () << 1, size);
+}
+
+template <typename T>
+void 
+PacketMetadata::RemoveHeader (T const &header, uint32_t size)
+{
+  DoRemoveHeader (T::GetUid () << 1, size);
+}
+template <typename T>
+void 
+PacketMetadata::AddTrailer (T const &trailer, uint32_t size)
+{
+  DoAddTrailer (T::GetUid () << 1, size);
+}
+template <typename T>
+void 
+PacketMetadata::RemoveTrailer (T const &trailer, uint32_t size)
+{
+  DoRemoveTrailer (T::GetUid () << 1, size);
+}
+
+
+PacketMetadata::PacketMetadata (uint32_t uid, uint32_t size)
+  : m_data (m_data = PacketMetadata::Create (10)),
+    m_head (0xffff),
+    m_tail (0xffff),
+    m_used (0),
+    m_packetUid (uid)
+{
+  memset (m_data->m_data, 0xff, 4);
+  if (size > 0)
+    {
+      DoAddHeader (0, size);
+    }
+}
+PacketMetadata::PacketMetadata (PacketMetadata const &o)
+  : m_data (o.m_data),
+    m_head (o.m_head),
+    m_tail (o.m_tail),
+    m_used (o.m_used),
+    m_packetUid (o.m_packetUid)
+{
+  NS_ASSERT (m_data != 0);
+  m_data->m_count++;
+}
+PacketMetadata &
+PacketMetadata::operator = (PacketMetadata const& o)
+{
+  if (m_data != o.m_data) 
+    {
+      // not self assignment
+      NS_ASSERT (m_data != 0);
+      m_data->m_count--;
+      if (m_data->m_count == 0) 
+        {
+          PacketMetadata::Recycle (m_data);
+        }
+      m_data = o.m_data;
+      NS_ASSERT (m_data != 0);
+      m_data->m_count++;
+    }
+  m_head = o.m_head;
+  m_tail = o.m_tail;
+  m_used = o.m_used;
+  m_packetUid = o.m_packetUid;
+  return *this;
+}
+PacketMetadata::~PacketMetadata ()
+{
+  NS_ASSERT (m_data != 0);
+  m_data->m_count--;
+  if (m_data->m_count == 0) 
+    {
+      PacketMetadata::Recycle (m_data);
+    }
+}
+
+}; // namespace ns3
+
+
+#endif /* PACKET_METADATA_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/packet-printer.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,135 @@
+/* -*- 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
+ * 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 "packet-printer.h"
+#include "chunk-registry.h"
+
+namespace ns3 {
+
+PacketPrinter::PacketPrinter ()
+  : m_forward (true),
+    m_separator (" ")
+{}
+
+void 
+PacketPrinter::PrintForward (void)
+{
+  m_forward = true;
+}
+void 
+PacketPrinter::PrintBackward (void)
+{
+  m_forward = false;
+}
+void
+PacketPrinter::SetSeparator (std::string separator)
+{
+  m_separator = separator;
+}
+void 
+PacketPrinter::SetPayloadPrinter (PayloadPrinter printer)
+{
+  m_payloadPrinter = printer;
+}
+
+void 
+PacketPrinter::PrintChunk (uint32_t chunkUid, 
+                           Buffer::Iterator start, 
+                           std::ostream &os, 
+                           uint32_t packetUid,
+                           uint32_t size) const
+{
+  uint8_t *instance = ChunkRegistry::GetStaticInstance (chunkUid);
+  ChunkRegistry::Deserialize (chunkUid, instance, start);
+
+  for (PrinterList::const_iterator i = m_printerList.begin (); i != m_printerList.end (); i++)
+    {
+      if (i->m_chunkUid == chunkUid)
+        {
+          ChunkRegistry::InvokePrintCallback (chunkUid, instance, os, packetUid, size, i->m_printer);
+          return;
+        }
+    }
+  // if the over did not override this type of chunk,
+  // we print something by default.
+  std::string name = ChunkRegistry::GetName (chunkUid, instance);
+  os << name;
+  ChunkRegistry::Print (chunkUid, instance, os);
+}
+void 
+PacketPrinter::PrintChunkFragment (uint32_t chunkUid,
+                                   std::ostream &os,
+                                   uint32_t packetUid,
+                                   uint32_t size,
+                                   uint32_t fragmentStart,
+                                   uint32_t fragmentEnd) const
+{
+  uint8_t *instance = ChunkRegistry::GetStaticInstance (chunkUid);
+  std::string name = ChunkRegistry::GetName (chunkUid, instance);
+  struct PacketPrinter::FragmentInformation info;
+  info.start = fragmentStart;
+  info.end = fragmentEnd;
+  for (PrinterList::const_iterator i = m_printerList.begin (); i != m_printerList.end (); i++)
+    {
+      if (i->m_chunkUid == chunkUid)
+        {
+
+          i->m_fragmentPrinter (os, packetUid, size, name, info);
+          return;
+        }
+    }
+  // if the user did not override this type of chunk,
+  // we print something by default.
+  NS_ASSERT (info.start != 0 || info.end != 0);
+  os << name << " "
+     << "("
+     << "length " << size - (info.end + info.start) << " "
+     << "trim_start " << info.start << " "
+     << "trim_end " << info.end
+     << ")";
+}
+void 
+PacketPrinter::PrintPayload (std::ostream &os, uint32_t packetUid, uint32_t size,
+                             uint32_t fragmentStart, uint32_t fragmentEnd) const
+{
+  struct PacketPrinter::FragmentInformation info;
+  info.start = fragmentStart;
+  info.end = fragmentEnd;
+  if (!m_payloadPrinter.IsNull ())
+    {
+      m_payloadPrinter (os, packetUid, size, info);
+      return;
+    }
+  // if the user did not override the payload printer,
+  // we print something anyway.
+  os << "DATA ("
+     << "length " << size - (info.end + info.start);
+  if (info.start != 0 || info.end != 0)
+    {
+      os << " "
+         << "trim_start " << info.start << " "
+         << "trim_end " << info.end;
+    }
+  os << ")";
+
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/packet-printer.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,181 @@
+/* -*- 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
+ * 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 PACKET_PRINTER_H
+#define PACKET_PRINTER_H
+
+#include "ns3/callback.h"
+#include "ns3/ptr.h"
+#include "buffer.h"
+#include <vector>
+
+namespace ns3 {
+
+/**
+ * \brief hold a list of print callbacks for packet headers and trailers
+ *
+ * Users can register in instances of this class print callbacks
+ * which are used by Packet::Print to print the content of a packet.
+ */
+class PacketPrinter 
+{
+public:
+  /**
+   * \brief indicates how many bytes were trimmed from a header
+   * or a trailer.
+   */
+  struct FragmentInformation
+  {
+    /**
+     * The number of bytes trimmed from the start of the header or the trailer.
+     */
+    uint32_t start;
+    /**
+     * The number of bytes trimmed from the end of the header or the trailer.
+     */
+    uint32_t end;
+  };
+  /**
+   * \brief callback to print payload.
+   *
+   * Arguments: output stream, packet uid, size, fragment information
+   */
+  typedef Callback<void,std::ostream &,uint32_t,uint32_t,struct PacketPrinter::FragmentInformation>
+    PayloadPrinter;
+
+  /**
+   * \brief callback to print fragmented chunks.
+   *
+   * Arguments: output stream, packet uid, size, header/trailer name, fragment information
+   */
+  typedef Callback<void,std::ostream &,uint32_t,uint32_t,std::string &,struct PacketPrinter::FragmentInformation>
+    ChunkFragmentPrinter;
+
+  /**
+   * \brief callback to print chunks for which no specific callback was specified.
+   *
+   * Arguments: output stream, packet uid, size, header/trailer name, fragment information
+   */
+  typedef Callback<void,std::ostream&,uint32_t,uint32_t,std::string&,struct PacketPrinter::FragmentInformation> 
+    DefaultPrinter;
+
+  PacketPrinter ();
+
+  /**
+   * Print the content of the packet forward.
+   */
+  void PrintForward (void);
+  /**
+   * Print the content of the packet backward.
+   */
+  void PrintBackward (void);
+  /**
+   * \param separator the new separator
+   *
+   * The default separator is a single space character.
+   */
+  void SetSeparator (std::string separator);
+  /**
+   * \param printer printer for payload
+   */
+  void SetPayloadPrinter (PayloadPrinter printer);
+  /**
+   * \param printer printer for the specified chunk
+   * \param fragmentPrinter printer for a fragment of the specified chunk
+   *
+   * If the user does not force a user-specific printing function through
+   * a call to SetHeaderPrinter, the default print output is generated.
+   */
+  template <typename T>
+  void SetHeaderPrinter (Callback<void,std::ostream &,uint32_t,uint32_t,const T *> printer,
+                         ChunkFragmentPrinter fragmentPrinter);
+  /**
+   * \param printer printer for the specified chunk
+   * \param fragmentPrinter printer for a fragment of the specified chunk
+   *
+   * If the user does not force a user-specific printing function through
+   * a call to SetTrailerPrinter, the default print output is generated.
+   */
+  template <typename T>
+  void SetTrailerPrinter (Callback<void,std::ostream &,uint32_t,uint32_t,const T *> printer,
+                          ChunkFragmentPrinter fragmentPrinter);  
+private:
+  friend class PacketMetadata;
+  void PrintChunk (uint32_t uid, 
+		   Buffer::Iterator i, 
+		   std::ostream &os, 
+		   uint32_t packetUid,
+		   uint32_t size) const;
+  void PrintChunkFragment (uint32_t uid,
+			   std::ostream &os,
+			   uint32_t packetUid,
+			   uint32_t size,
+			   uint32_t fragmentStart,
+			   uint32_t fragmentEnd) const;
+  void PrintPayload (std::ostream &os, uint32_t packetUid, uint32_t size,
+		     uint32_t fragmentStart, uint32_t fragmentEnd) const;
+  struct Printer
+  {
+    uint32_t m_chunkUid;
+    Ptr<CallbackImplBase> m_printer;
+    Callback<void,std::ostream &,uint32_t,uint32_t,std::string &,
+             struct PacketPrinter::FragmentInformation> m_fragmentPrinter;
+  };
+  typedef std::vector<struct PacketPrinter::Printer> PrinterList;
+  
+  PrinterList m_printerList;
+  PayloadPrinter m_payloadPrinter;
+  DefaultPrinter m_defaultPrinter;
+  bool m_forward;
+  std::string m_separator;
+};
+
+} // namespace ns3
+
+namespace ns3 {
+
+template <typename T>
+void 
+PacketPrinter::SetHeaderPrinter (Callback<void,std::ostream &,uint32_t,uint32_t,const T *> printer,
+                                 ChunkFragmentPrinter fragmentPrinter)
+{
+  Printer p;
+  p.m_chunkUid = T::GetUid ();
+  p.m_printer = printer.GetImpl ();
+  p.m_fragmentPrinter = fragmentPrinter;
+  m_printerList.push_back (p);
+}
+
+template <typename T>
+void 
+PacketPrinter::SetTrailerPrinter (Callback<void,std::ostream &,uint32_t,uint32_t,const T *> printer,
+                                 ChunkFragmentPrinter fragmentPrinter)
+{
+  Printer p;
+  p.m_chunkUid = T::GetUid ();
+  p.m_printer = printer.GetImpl ();
+  p.m_fragmentPrinter = fragmentPrinter;
+  m_printerList.push_back (p);
+}
+
+
+} // namespace ns3
+
+#endif /* PACKET_PRINTER_H */
--- a/src/common/packet.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/common/packet.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -19,6 +19,7 @@
  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
  */
 #include "packet.h"
+#include "packet-printer.h"
 #include "ns3/assert.h"
 
 namespace ns3 {
@@ -27,20 +28,20 @@
 
 Packet::Packet ()
   : m_buffer (),
-    m_uid (m_globalUid)
+    m_metadata (m_globalUid, 0)
 {
   m_globalUid++;
 }
 
 Packet::Packet (uint32_t size)
   : m_buffer (size),
-    m_uid (m_globalUid)
+    m_metadata (m_globalUid, size)
 {
   m_globalUid++;
 }
 Packet::Packet (uint8_t const*buffer, uint32_t size)
   : m_buffer (),
-    m_uid (m_globalUid)
+    m_metadata (m_globalUid, size)
 {
   m_globalUid++;
   m_buffer.AddAtStart (size);
@@ -48,17 +49,20 @@
   i.Write (buffer, size);
 }
 
-Packet::Packet (Buffer buffer, Tags tags, uint32_t uid)
+Packet::Packet (Buffer buffer, Tags tags, PacketMetadata metadata)
   : m_buffer (buffer),
     m_tags (tags),
-    m_uid (uid)
+    m_metadata (metadata)
 {}
 
 Packet 
 Packet::CreateFragment (uint32_t start, uint32_t length) const
 {
   Buffer buffer = m_buffer.CreateFragment (start, length);
-  return Packet (buffer, m_tags, m_uid);
+  NS_ASSERT (m_buffer.GetSize () >= start + length);
+  uint32_t end = m_buffer.GetSize () - (start + length);
+  PacketMetadata metadata = m_metadata.CreateFragment (start, end);
+  return Packet (buffer, m_tags, metadata);
 }
 
 uint32_t 
@@ -70,30 +74,37 @@
 void 
 Packet::AddAtEnd (Packet packet)
 {
-  Buffer src = packet.m_buffer;
-  m_buffer.AddAtEnd (src.GetSize ());
-  Buffer::Iterator destStart = m_buffer.End ();
+  Buffer src = packet.m_buffer.CreateFullCopy ();
+  Buffer dst = m_buffer.CreateFullCopy ();
+
+  dst.AddAtEnd (src.GetSize ());
+  Buffer::Iterator destStart = dst.End ();
   destStart.Prev (src.GetSize ());
   destStart.Write (src.Begin (), src.End ());
+  m_buffer = dst;
   /**
    * XXX: we might need to merge the tag list of the
    * other packet into the current packet.
    */
+  m_metadata.AddAtEnd (packet.m_metadata);
 }
 void
 Packet::AddPaddingAtEnd (uint32_t size)
 {
   m_buffer.AddAtEnd (size);
+  m_metadata.AddPaddingAtEnd (size);
 }
 void 
 Packet::RemoveAtEnd (uint32_t size)
 {
   m_buffer.RemoveAtEnd (size);
+  m_metadata.RemoveAtEnd (size);
 }
 void 
 Packet::RemoveAtStart (uint32_t size)
 {
   m_buffer.RemoveAtStart (size);
+  m_metadata.RemoveAtStart (size);
 }
 
 void 
@@ -111,14 +122,91 @@
 uint32_t 
 Packet::GetUid (void) const
 {
-  return m_uid;
+  return m_metadata.GetUid ();
+}
+
+void 
+Packet::PrintTags (std::ostream &os) const
+{
+  m_tags.Print (os, " ");
 }
 
 void 
 Packet::Print (std::ostream &os) const
-{}
+{
+  m_metadata.Print (os, m_buffer, PacketPrinter ());
+}
+
+void 
+Packet::Print (std::ostream &os, const PacketPrinter &printer) const
+{
+  m_metadata.Print (os, m_buffer, printer);
+}
+
+void
+Packet::EnableMetadata (void)
+{
+  PacketMetadata::Enable ();
+}
+
+Buffer 
+Packet::Serialize (void) const
+{
+  Buffer buffer;
+  uint32_t reserve;
+
+  // write metadata
+  reserve = m_metadata.GetSerializedSize ();
+  buffer.AddAtStart (reserve);
+  m_metadata.Serialize (buffer.Begin (), reserve);
 
-}; // namespace ns3
+  // write tags
+  reserve = m_tags.GetSerializedSize ();
+  buffer.AddAtStart (reserve);
+  m_tags.Serialize (buffer.Begin (), reserve);
+  
+  // aggregate byte buffer, metadata, and tags
+  Buffer tmp = m_buffer.CreateFullCopy ();
+  buffer.AddAtStart (tmp.GetSize ());
+  buffer.Begin ().Write (tmp.Begin (), tmp.End ());
+  
+  // write byte buffer size.
+  buffer.AddAtStart (4);
+  buffer.Begin ().WriteU32 (m_buffer.GetSize ());
+
+  return buffer;
+}
+void 
+Packet::Deserialize (Buffer buffer)
+{
+  Buffer buf = buffer;
+  // read size
+  uint32_t packetSize = buf.Begin ().ReadU32 ();
+  buf.RemoveAtStart (4);
+
+  // read buffer.
+  buf.RemoveAtEnd (buf.GetSize () - packetSize);
+  m_buffer = buf;
+
+  // read tags
+  buffer.RemoveAtStart (4 + packetSize);
+  uint32_t tagsDeserialized = m_tags.Deserialize (buffer.Begin ());
+  buffer.RemoveAtStart (tagsDeserialized);
+
+  // read metadata
+  uint32_t metadataDeserialized = 
+    m_metadata.Deserialize (buffer.Begin ());
+  buffer.RemoveAtStart (metadataDeserialized);
+}
+
+std::ostream& operator<< (std::ostream& os, const Packet &packet)
+{
+  packet.Print (os);
+  return os;
+}
+
+
+} // namespace ns3
 
 
 
@@ -161,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/common/packet.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/common/packet.h	Fri Sep 28 11:59:46 2007 +0100
@@ -26,20 +26,27 @@
 #include "header.h"
 #include "trailer.h"
 #include "tags.h"
+#include "packet-metadata.h"
+#include "tag.h"
 #include "ns3/callback.h"
 #include "ns3/assert.h"
 
 namespace ns3 {
 
+class PacketPrinter;
+
 /**
  * \brief network packets
  *
- * Each network packet contains a byte buffer and a list of tags.
+ * Each network packet contains a byte buffer, a list of tags, and
+ * metadata.
+ *
  * - The byte buffer stores the serialized content of the headers and trailers 
  * added to a packet. The serialized representation of these headers is expected
  * to match that of real network packets bit for bit (although nothing
  * forces you to do this) which means that the content of a packet buffer
  * is expected to be that of a real packet.
+ *
  * - The list of tags stores an arbitrarily large set of arbitrary 
  * user-provided data structures in the packet: only one instance of
  * each type of data structure is allowed in a list of tags. 
@@ -48,43 +55,22 @@
  * 16 bytes big. Trying to attach bigger data structures will trigger
  * crashes at runtime.
  *
- * Implementing a new type of Header for a new protocol is pretty easy
- * and is a matter of creating a subclass of the ns3::Header base class,
- * and implementing the 4 pure virtual methods defined in ns3::Header.
- * Sample code which shows how to create such a new Header, how to use
- * it, and how to manipulate tags is shown below:
- * \include samples/main-packet.cc
- *
- * The current implementation of the byte buffers and tag list is based
- * on COW (Copy On Write. An introduction to COW can be found in Scott 
- * Meyer's "More Effective C++", items 17 and 29). What this means is that
- * copying packets without modifying them is very cheap (in terms of cpu
- * and memory usage) and modifying them can be also very cheap. What is 
- * key for proper COW implementations is being
- * able to detect when a given modification of the state of a packet triggers
- * a full copy of the data prior to the modification: COW systems need
- * to detect when an operation is "dirty".
+ * - The metadata describes the type of the headers and trailers which
+ * were serialized in the byte buffer. The maintenance of metadata is
+ * optional and disabled by default. To enable it, you must call
+ * Packet::EnableMetadata and this will allow you to get non-empty
+ * output from Packet::Print and Packet::Print.
  *
- * Dirty operations:
- *   - ns3::Packet::RemoveTag
- *   - ns3::Packet::Add
- *   - both versions of ns3::Packet::AddAtEnd
+ * Implementing a new type of Header or Trailer for a new protocol is 
+ * pretty easy and is a matter of creating a subclass of the ns3::Header 
+ * or of the ns3::Trailer base class, and implementing the methods
+ * described in their respective API documentation.
  *
- * Non-dirty operations:
- *   - ns3::Packet::AddTag
- *   - ns3::Packet::RemoveAllTags
- *   - ns3::Packet::PeekTag
- *   - ns3::Packet::Peek
- *   - ns3::Packet::Remove
- *   - ns3::Packet::CreateFragment
- *   - ns3::Packet::RemoveAtStart
- *   - ns3::Packet::RemoveAtEnd
+ * Implementing a new type of Tag requires roughly the same amount of
+ * work and this work is described in the ns3::Tag API documentation.
  *
- * Dirty operations will always be slower than non-dirty operations,
- * sometimes by several orders of magnitude. However, even the
- * dirty operations have been optimized for common use-cases which
- * means that most of the time, these operations will not trigger
- * data copies and will thus be still very fast.
+ * The performance aspects of the Packet API are discussed in 
+ * \ref packetperf
  */
 class Packet {
 public:
@@ -129,7 +115,7 @@
   uint32_t GetSize (void) const;
   /**
    * Add header to this packet. This method invokes the
-   * ns3::Header::GetSerializedSize and ns3::Header::SerializeTo 
+   * GetSerializedSize and Serialize
    * methods to reserve space in the buffer and request the 
    * header to serialize itself in the packet buffer.
    *
@@ -139,8 +125,7 @@
   void AddHeader (T const &header);
   /**
    * Deserialize and remove the header from the internal buffer.
-   * This method invokes ns3::Header::DeserializeFrom
-   * and then removes the deserialized bytes from the buffer.
+   * This method invokes Deserialize.
    *
    * \param header a reference to the header to remove from the internal buffer.
    * \returns the number of bytes removed from the packet.
@@ -149,7 +134,7 @@
   uint32_t RemoveHeader (T &header);
   /**
    * Add trailer to this packet. This method invokes the
-   * ns3::Trailer::GetSerializedSize and ns3::Trailer::serializeTo 
+   * GetSerializedSize and Serialize
    * methods to reserve space in the buffer and request the trailer 
    * to serialize itself in the packet buffer.
    *
@@ -159,8 +144,7 @@
   void AddTrailer (T const &trailer);
   /**
    * Remove a deserialized trailer from the internal buffer.
-   * This method invokes the ns3::Trailer::DeserializeFrom method
-   * and then removes the deserialized bytes from the buffer.
+   * This method invokes the Deserialize method.
    *
    * \param trailer a reference to the trailer to remove from the internal buffer.
    * \returns the number of bytes removed from the end of the packet.
@@ -170,7 +154,8 @@
   /**
    * Attach a tag to this packet. The tag is fully copied
    * in a packet-specific internal buffer. This operation 
-   * is expected to be really fast.
+   * is expected to be really fast. The copy constructor of the
+   * tag is invoked to copy it into the tag buffer.
    *
    * \param tag a pointer to the tag to attach to this packet.
    */
@@ -197,6 +182,8 @@
   /**
    * Copy a tag stored internally to the input tag. If no instance
    * of this tag is present internally, the input tag is not modified.
+   * The copy constructor of the tag is invoked to copy it into the 
+   * input tag variable.
    *
    * \param tag a pointer to the tag to read from this packet
    * \returns true if an instance of this tag type is stored
@@ -210,6 +197,14 @@
    */
   void RemoveAllTags (void);
   /**
+   * \param os output stream in which the data should be printed.
+   *
+   * Iterate over the tags present in this packet, and
+   * invoke the Print method of each tag stored in the packet.
+   */
+  void PrintTags (std::ostream &os) const;
+
+  /**
    * Concatenate the input packet at the end of the current
    * packet. This does not alter the uid of either packet.
    *
@@ -254,16 +249,123 @@
    */
   uint32_t GetUid (void) const;
 
+  /**
+   * \param os output stream in which the data should be printed.
+   *
+   * Iterate over the headers and trailers present in this packet, 
+   * from the first header to the last trailer and invoke, for
+   * each of them, the user-provided method Header::DoPrint or 
+   * Trailer::DoPrint methods.
+   */
   void Print (std::ostream &os) const;
+  /**
+   * \param os output stream in which the data should be printed.
+   * \param printer the output formatter to use to print
+   *        the content of this packet.
+   *
+   * Iterate over the headers and trailers present in this packet,
+   * either in the "forward" (first header to last trailer) or in
+   * the "backward" (last trailer to first header) direction, as
+   * specified by the PacketPrinter::PrintForward or the
+   * PacketPrinter::PrintBackward methods. For each header, trailer,
+   * or fragment of a header or a trailer, invoke the user-specified
+   * print callback stored in the specified PacketPrinter.
+   */
+  void Print (std::ostream &os, const PacketPrinter &printer) const;
+
+  /**
+   * By default, packets do not keep around enough metadata to
+   * perform the operations requested by the Print methods. If you
+   * want to be able to invoke any of the two ::Print methods, 
+   * you need to invoke this method at least once during the 
+   * simulation setup and before any packet is created.
+   *
+   * The packet metadata is also used to perform extensive
+   * sanity checks at runtime when performing operations on a 
+   * Packet. For example, this metadata is used to verify that
+   * when you remove a header from a packet, this same header
+   * was actually present at the front of the packet. These
+   * errors will be detected and will abort the program.
+   */
+  static void EnableMetadata (void);
+
+  /**
+   * \returns a byte buffer
+   *
+   * This method creates a serialized representation of a Packet object
+   * ready to be transmitted over a network to another system. This
+   * serialized representation contains a copy of the packet byte buffer,
+   * the tag list, and the packet metadata (if there is one).
+   *
+   * This method will trigger calls to the Serialize and GetSerializedSize
+   * methods of each tag stored in this packet.
+   *
+   * This method will typically be used by parallel simulations where
+   * the simulated system is partitioned and each partition runs on
+   * a different CPU.
+   */
+  Buffer Serialize (void) const;
+  /**
+   * \param buffer a byte buffer
+   *
+   * This method reads a byte buffer as created by Packet::Serialize
+   * and restores the state of the Packet to what it was prior to
+   * calling Serialize.
+   *
+   * This method will trigger calls to the Deserialize method
+   * of each tag stored in this packet.
+   *
+   * This method will typically be used by parallel simulations where
+   * the simulated system is partitioned and each partition runs on
+   * a different CPU.
+   */
+  void Deserialize (Buffer buffer);
 private:
-  Packet (Buffer buffer, Tags tags, uint32_t uid);
+  Packet (Buffer buffer, Tags tags, PacketMetadata metadata);
   Buffer m_buffer;
   Tags m_tags;
-  uint32_t m_uid;
+  PacketMetadata m_metadata;
   static uint32_t m_globalUid;
 };
 
-}; // namespace ns3
+std::ostream& operator<< (std::ostream& os, const Packet &packet);
+
+/**
+ * \defgroup packetperf Packet Performance
+ * The current implementation of the byte buffers and tag list is based
+ * on COW (Copy On Write. An introduction to COW can be found in Scott 
+ * Meyer's "More Effective C++", items 17 and 29). What this means is that
+ * copying packets without modifying them is very cheap (in terms of cpu
+ * and memory usage) and modifying them can be also very cheap. What is 
+ * key for proper COW implementations is being
+ * able to detect when a given modification of the state of a packet triggers
+ * a full copy of the data prior to the modification: COW systems need
+ * to detect when an operation is "dirty".
+ *
+ * Dirty operations:
+ *   - ns3::Packet::RemoveTag
+ *   - ns3::Packet::AddHeader
+ *   - ns3::Packet::AddTrailer
+ *   - both versions of ns3::Packet::AddAtEnd
+ *
+ * Non-dirty operations:
+ *   - ns3::Packet::AddTag
+ *   - ns3::Packet::RemoveAllTags
+ *   - ns3::Packet::PeekTag
+ *   - ns3::Packet::RemoveHeader
+ *   - ns3::Packet::RemoveTrailer
+ *   - ns3::Packet::CreateFragment
+ *   - ns3::Packet::RemoveAtStart
+ *   - ns3::Packet::RemoveAtEnd
+ *
+ * Dirty operations will always be slower than non-dirty operations,
+ * sometimes by several orders of magnitude. However, even the
+ * dirty operations have been optimized for common use-cases which
+ * means that most of the time, these operations will not trigger
+ * data copies and will thus be still very fast.
+ */
+
+} // namespace ns3
 
 
 /**************************************************
@@ -277,41 +379,53 @@
 void
 Packet::AddHeader (T const &header)
 {
-  NS_ASSERT_MSG (dynamic_cast<Header const *> (&header) != 0, 
-                 "Must pass Header subclass to Packet::AddHeader");
-  uint32_t size = header.GetSize ();
+  const Header *testHeader;
+  // if the following assignment fails, it is because the 
+  // input to this function is not a subclass of the Header class
+  testHeader = &header;
+  uint32_t size = header.GetSerializedSize ();
   m_buffer.AddAtStart (size);
   header.Serialize (m_buffer.Begin ());
+  m_metadata.AddHeader (header, size);
 }
 template <typename T>
 uint32_t
 Packet::RemoveHeader (T &header)
 {
-  NS_ASSERT_MSG (dynamic_cast<Header const *> (&header) != 0, 
-                 "Must pass Header subclass to Packet::RemoveHeader");
+  Header *testHeader;
+  // if the following assignment fails, it is because the 
+  // input to this function is not a subclass of the Header class
+  testHeader = &header;
   uint32_t deserialized = header.Deserialize (m_buffer.Begin ());
   m_buffer.RemoveAtStart (deserialized);
+  m_metadata.RemoveHeader (header, deserialized);
   return deserialized;
 }
 template <typename T>
 void
 Packet::AddTrailer (T const &trailer)
 {
-  NS_ASSERT_MSG (dynamic_cast<Trailer const *> (&trailer) != 0, 
-                 "Must pass Trailer subclass to Packet::AddTrailer");
-  uint32_t size = trailer.GetSize ();
+  const Trailer *testTrailer;
+  // if the following assignment fails, it is because the 
+  // input to this function is not a subclass of the Trailer class
+  testTrailer = &trailer;
+  uint32_t size = trailer.GetSerializedSize ();
   m_buffer.AddAtEnd (size);
   Buffer::Iterator end = m_buffer.End ();
   trailer.Serialize (end);
+  m_metadata.AddTrailer (trailer, size);
 }
 template <typename T>
 uint32_t
 Packet::RemoveTrailer (T &trailer)
 {
-  NS_ASSERT_MSG (dynamic_cast<Trailer const *> (&trailer) != 0, 
-                 "Must pass Trailer subclass to Packet::RemoveTrailer");
+  Trailer *testTrailer;
+  // if the following assignment fails, it is because the 
+  // input to this function is not a subclass of the Trailer class
+  testTrailer = &trailer;
   uint32_t deserialized = trailer.Deserialize (m_buffer.End ());
   m_buffer.RemoveAtEnd (deserialized);
+  m_metadata.RemoveTrailer (trailer, deserialized);
   return deserialized;
 }
 
@@ -319,18 +433,31 @@
 template <typename T>
 void Packet::AddTag (T const& tag)
 {
+  const Tag *parent;
+  // if the following assignment fails, it is because the
+  // input to this function is not a subclass of the Tag class.
+  parent = &tag;
   m_tags.Add (tag);
 }
 template <typename T>
 bool Packet::RemoveTag (T & tag)
 {
+  Tag *parent;
+  // if the following assignment fails, it is because the
+  // input to this function is not a subclass of the Tag class.
+  parent = &tag;
   return m_tags.Remove (tag);
 }
 template <typename T>
 bool Packet::PeekTag (T & tag) const
 {
+  Tag *parent;
+  // if the following assignment fails, it is because the
+  // input to this function is not a subclass of the Tag class.
+  parent = &tag;
   return m_tags.Peek (tag);
 }
-}; // namespace ns3
+
+} // namespace ns3
 
 #endif /* PACKET_H */
--- a/src/common/stream-tracer-test.cc	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,68 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2006 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
- * 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 "stream-tracer.h"
-#include "ns3/test.h"
-#include <iostream>
-
-#ifdef RUN_SELF_TESTS
-
-namespace {
-
-class TestStreamTracer : public ns3::Test {
-public:
-  TestStreamTracer ();
-  virtual bool RunTests (void);
-};
-
-static TestStreamTracer gTestStream;
-
-TestStreamTracer::TestStreamTracer ()
-  : Test ("StreamTracer")
-{}
-
-bool
-TestStreamTracer::RunTests (void)
-{
-  bool ok = true;
-  ns3::StreamTracer trace;
-  //trace.setStream (&std::cout);
-  trace << 1;
-  trace << " X ";
-  trace << 1.0;
-  trace << std::endl;
-  trace << "test ";
-  trace << 1 << " test";
-  trace << "test "
-        << 1.0 << " "
-        << 0xdeadbead
-        << std::endl;
-  trace << "0x" << std::hex 
-        << 0xdeadbeaf 
-        << std::dec << " "
-        << 0xdeadbeaf
-        << std::endl;
-  return ok;
-}
-
-
-}; // namespace ns3
-
-#endif /* RUN_SELF_TESTS */
--- a/src/common/stream-tracer.h	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2006 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
- * 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 STREAM_TRACER_H
-#define STREAM_TRACER_H
-
-#include <ostream>
-
-namespace ns3 {
-
-/**
- * \brief log arbitrary data to std::ostreams
- * 
- * Whenever operator << is invoked on this class,
- * it is forwarded to the stored std::ostream output
- * stream (if there is one).
- */
-class StreamTracer {
-public:
-  StreamTracer ()
-      : m_os (0) {}
-  template <typename T>
-  StreamTracer &operator << (T const&v) {
-      if (m_os != 0) 
-        {
-          (*m_os) << v;
-        }
-      return *this;
-  }
-  template <typename T>
-  StreamTracer &operator << (T &v) {
-      if (m_os != 0) 
-        {
-          (*m_os) << v;
-        }
-      return *this;
-  }
-  StreamTracer &operator << (std::ostream &(*v) (std::ostream &)) {
-      if (m_os != 0) 
-        {
-          (*m_os) << v;
-        }
-      return *this;
-  }
-
-  /**
-   * \param os the output stream to store
-   */
-  void SetStream (std::ostream * os) {
-      m_os = os;
-  }
-private:
-  std::ostream *m_os;
-};
-
-}; // namespace ns3
-
-
-#endif /* TRACER_STREAM_H */
--- a/src/common/sv-trace-source.h	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,242 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2006 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
- * 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 SV_TRACE_SOURCE_H
-#define SV_TRACE_SOURCE_H
-
-#include "callback-trace-source.h"
-#include <stdint.h>
-
-namespace ns3 {
-
-class SVTraceSourceBase {
-public:
-  typedef CallbackTraceSource<int64_t, int64_t> ChangeNotifyCallback;
-
-  SVTraceSourceBase () {}
-  SVTraceSourceBase (SVTraceSourceBase const &o) {}
-  SVTraceSourceBase &operator = (SVTraceSourceBase const &o) {
-      return *this;
-  }
-
-  ~SVTraceSourceBase () {}
-
-  void AddCallback (CallbackBase const & callback, TraceContext const & context) {
-    m_callback.AddCallback (callback, context);
-  }
-  void RemoveCallback (CallbackBase const & callback) {
-    m_callback.RemoveCallback (callback);
-  }
-protected:
-  void Notify (int64_t oldVal, int64_t newVal) {
-      if (oldVal != newVal) 
-        {
-          m_callback (oldVal, newVal);
-        }
-  }
-private:
-  ChangeNotifyCallback m_callback;
-};
-
-template <typename T>
-class UVTraceSource;
-
-
-/**
- * \brief trace variables of type "signed integer"
- * \ingroup lowleveltracing
- *
- * This template class implements a POD type: it
- * behaves like any other variable of type "signed integer"
- * except that it also reports any changes to its
- * value with its internal callback.
- *
- * To instantiate a 32-bit signed variable (to store
- * a TCP counter for example), you would create a variable of type
- * ns3::UVTraceSource<int32_t> :
- \code
- #include <stdint.h>
- #include "ns3/sv-trace-source.h"
-
- ns3::SVTraceSource<uint16_t> var;
- \endcode
- * and you would use it like any other variable of type int32_t:
- \code
- var += 12;
- var = 10;
- var = -10;
- \endcode
- */
-template <typename T>
-class SVTraceSource : public SVTraceSourceBase {
-public:
-  SVTraceSource ()
-      : m_var (0)
-  {}
-  SVTraceSource (T const &var) 
-      : m_var (var)
-  {}
-
-  SVTraceSource &operator = (SVTraceSource const &o) {
-      Assign (o.Get ());
-      return *this;
-  }
-  template <typename TT>
-  SVTraceSource &operator = (SVTraceSource<TT> const &o) {
-      Assign (o.Get ());
-      return *this;
-  }
-  template <typename TT>
-  SVTraceSource &operator = (UVTraceSource<TT> const &o) {
-      Assign (o.Get ());
-      return *this;
-  }
-  SVTraceSource &operator++ () {
-      Assign (Get () + 1);
-      return *this;
-  }
-  SVTraceSource &operator-- () {
-      Assign (Get () - 1);
-      return *this;
-  }
-  SVTraceSource operator++ (int) {
-      SVTraceSource old (*this);
-      ++*this;
-      return old;
-  }
-  SVTraceSource operator-- (int) {
-      SVTraceSource old (*this);
-      --*this;
-      return old;
-  }
-  operator T () const {
-      return Get ();
-  }
-
-
-  void Assign (T var) {
-      Notify (m_var, var);
-      m_var = var;
-  }
-  T Get (void) const {
-      return m_var;
-  }
-
-private:
-  T m_var;
-};
-
-template <typename T>
-SVTraceSource<T> &operator += (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
-  lhs.Assign (lhs.Get () + rhs.Get ());
-  return lhs;
-}
-template <typename T>
-SVTraceSource<T> &operator -= (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
-  lhs.Assign (lhs.Get () - rhs.Get ());
-  return lhs;
-}
-template <typename T>
-SVTraceSource<T> &operator *= (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
-  lhs.Assign (lhs.Get () * rhs.Get ());
-  return lhs;
-}
-template <typename T>
-SVTraceSource<T> &operator /= (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
-  lhs.Assign (lhs.Get () / rhs.Get ());
-  return lhs;
-}
-template <typename T>
-SVTraceSource<T> &operator <<= (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
-  lhs.Assign (lhs.Get () << rhs.Get ());
-  return lhs;
-}
-template <typename T>
-SVTraceSource<T> &operator >>= (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
-  lhs.Assign (lhs.Get () >> rhs.Get ());
-  return lhs;
-}
-template <typename T>
-SVTraceSource<T> &operator &= (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
-  lhs.Assign (lhs.Get () & rhs.Get ());
-  return lhs;
-}
-template <typename T>
-SVTraceSource<T> &operator |= (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
-  lhs.Assign (lhs.Get () | rhs.Get ());
-  return lhs;
-}
-template <typename T>
-SVTraceSource<T> &operator ^= (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
-  lhs.Assign (lhs.Get () ^ rhs.Get ());
-  return lhs;
-}
-
-
-template <typename T, typename U>
-SVTraceSource<T> &operator += (SVTraceSource<T> &lhs, U const &rhs) {
-  lhs.Assign (lhs.Get () + rhs);
-  return lhs;
-}
-template <typename T, typename U>
-SVTraceSource<T> &operator -= (SVTraceSource<T> &lhs, U const &rhs) {
-  lhs.Assign (lhs.Get () - rhs);
-  return lhs;
-}
-template <typename T, typename U>
-SVTraceSource<T> &operator *= (SVTraceSource<T> &lhs, U const &rhs) {
-  lhs.Assign (lhs.Get () * rhs);
-  return lhs;
-}
-template <typename T, typename U>
-SVTraceSource<T> &operator /= (SVTraceSource<T> &lhs, U const &rhs) {
-  lhs.Assign (lhs.Get () / rhs);
-  return lhs;
-}
-template <typename T, typename U>
-SVTraceSource<T> &operator <<= (SVTraceSource<T> &lhs, U const &rhs) {
-  lhs.Assign (lhs.Get () << rhs);
-  return lhs;
-}
-template <typename T, typename U>
-SVTraceSource<T> &operator >>= (SVTraceSource<T> &lhs, U const &rhs) {
-  lhs.Assign (lhs.Get () >> rhs);
-  return lhs;
-}
-template <typename T, typename U>
-SVTraceSource<T> &operator &= (SVTraceSource<T> &lhs, U const &rhs) {
-  lhs.Assign (lhs.Get () & rhs);
-  return lhs;
-}
-template <typename T, typename U>
-SVTraceSource<T> &operator |= (SVTraceSource<T> &lhs, U const &rhs) {
-  lhs.Assign (lhs.Get () | rhs);
-  return lhs;
-}
-template <typename T, typename U>
-SVTraceSource<T> &operator ^= (SVTraceSource<T> &lhs, U const &rhs) {
-  lhs.Assign (lhs.Get () ^ rhs);
-  return lhs;
-}
-
-}; // namespace ns3
-
-#endif /* SV_TRACE_SOURCE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/tag-registry.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,87 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 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
+ * 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 "tag-registry.h"
+#include "ns3/fatal-error.h"
+
+namespace ns3 {
+
+TagRegistry::TagInfoVector *
+TagRegistry::GetInfo (void)
+{
+  static TagRegistry::TagInfoVector vector;
+  return &vector;
+}
+
+std::string
+TagRegistry::GetUidString (uint32_t uid)
+{
+  TagInfo info = (*GetInfo ())[uid - 1];
+  return info.uidString;
+}
+uint32_t 
+TagRegistry::GetUidFromUidString (std::string uidString)
+{
+  TagInfoVector *vec = GetInfo ();
+  uint32_t uid = 1;
+  for (TagInfoVector::iterator i = vec->begin (); i != vec->end (); i++)
+    {
+      if (i->uidString == uidString)
+        {
+          return uid;
+        }
+      uid++;
+    }
+  NS_FATAL_ERROR ("We are trying to deserialize an un-registered type. This can't work.");
+  return 0;
+}
+
+void 
+TagRegistry::Destruct (uint32_t uid, uint8_t *data)
+{
+  TagInfo info = (*GetInfo ())[uid - 1];
+  info.destruct (data);
+}
+void 
+TagRegistry::Print (uint32_t uid, uint8_t *data, std::ostream &os)
+{
+  TagInfo info = (*GetInfo ())[uid - 1];
+  info.print (data, os);
+}
+uint32_t
+TagRegistry::GetSerializedSize (uint32_t uid, uint8_t *data)
+{
+  TagInfo info = (*GetInfo ())[uid - 1];
+  return info.getSerializedSize (data);
+}
+void 
+TagRegistry::Serialize (uint32_t uid, uint8_t *data, Buffer::Iterator start)
+{
+  TagInfo info = (*GetInfo ())[uid - 1];
+  info.serialize (data, start);
+}
+uint32_t 
+TagRegistry::Deserialize (uint32_t uid, uint8_t *data, Buffer::Iterator start)
+{
+  TagInfo info = (*GetInfo ())[uid - 1];
+  return info.deserialize (data, start);
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/tag-registry.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,149 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 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
+ * 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 TAG_REGISTRY_H
+#define TAG_REGISTRY_H
+
+#include <string>
+#include <stdint.h>
+#include "buffer.h"
+
+namespace ns3 {
+
+/**
+ * \brief a registry of all existing tag types.
+ * \internal
+ *
+ * This class is used to give polymorphic access to the methods
+ * exported by a tag. It also is used to associate a single
+ * reliable uid to each unique type. 
+ */
+class TagRegistry
+{
+public:
+  template <typename T>
+  static uint32_t Register (std::string uidString);
+  static std::string GetUidString (uint32_t uid);
+  static uint32_t GetUidFromUidString (std::string uidString);
+  static void Destruct (uint32_t uid, uint8_t *data);
+  static void Print (uint32_t uid, uint8_t *data, std::ostream &os);
+  static uint32_t GetSerializedSize (uint32_t uid, uint8_t *data);
+  static void Serialize (uint32_t uid, uint8_t *data, Buffer::Iterator start);
+  static uint32_t Deserialize (uint32_t uid, uint8_t *data, Buffer::Iterator start);
+private:
+  typedef void (*DestructCb) (uint8_t *);
+  typedef void (*PrintCb) (uint8_t *, std::ostream &);
+  typedef uint32_t (*GetSerializedSizeCb) (uint8_t *);
+  typedef void (*SerializeCb) (uint8_t *, Buffer::Iterator);
+  typedef uint32_t (*DeserializeCb) (uint8_t *, Buffer::Iterator);
+  struct TagInfo
+  {
+    std::string uidString;
+    DestructCb destruct;
+    PrintCb print;
+    GetSerializedSizeCb getSerializedSize;
+    SerializeCb serialize;
+    DeserializeCb deserialize;
+  };
+  typedef std::vector<struct TagInfo> TagInfoVector;
+
+  template <typename T>
+  static void DoDestruct (uint8_t *data);
+  template <typename T>
+  static void DoPrint (uint8_t *data, std::ostream &os);
+  template <typename T>
+  static uint32_t DoGetSerializedSize (uint8_t *data);
+  template <typename T>
+  static void DoSerialize (uint8_t *data, Buffer::Iterator start);
+  template <typename T>
+  static uint32_t DoDeserialize (uint8_t *data, Buffer::Iterator start);
+
+  static TagInfoVector *GetInfo (void);
+};
+
+} // namespace ns3
+
+namespace ns3 {
+
+template <typename T>
+void 
+TagRegistry::DoDestruct (uint8_t *data)
+{
+  T *tag = reinterpret_cast<T *> (data);
+  tag->~T ();  
+}
+template <typename T>
+void 
+TagRegistry::DoPrint (uint8_t *data, std::ostream &os)
+{
+  T *tag = reinterpret_cast<T *> (data);
+  tag->Print (os);
+}
+template <typename T>
+uint32_t 
+TagRegistry::DoGetSerializedSize (uint8_t *data)
+{
+  T *tag = reinterpret_cast<T *> (data);
+  return tag->GetSerializedSize ();
+}
+template <typename T>
+void 
+TagRegistry::DoSerialize (uint8_t *data, Buffer::Iterator start)
+{
+  T *tag = reinterpret_cast<T *> (data);
+  tag->Serialize (start);
+}
+template <typename T>
+uint32_t 
+TagRegistry::DoDeserialize (uint8_t *data, Buffer::Iterator start)
+{
+  T *tag = reinterpret_cast<T *> (data);
+  return tag->Deserialize (start);
+}
+
+template <typename T>
+uint32_t 
+TagRegistry::Register (std::string uidString)
+{
+  TagInfoVector *vec = GetInfo ();
+  uint32_t j = 0;
+  for (TagInfoVector::iterator i = vec->begin (); i != vec->end (); i++)
+    {
+      if (i->uidString == uidString)
+        {
+          return j;
+        }
+      j++;
+    }
+  TagInfo info;
+  info.uidString = uidString;
+  info.destruct = &TagRegistry::DoDestruct<T>;
+  info.print = &TagRegistry::DoPrint<T>;
+  info.getSerializedSize = &TagRegistry::DoGetSerializedSize<T>;
+  info.serialize = &TagRegistry::DoSerialize<T>;
+  info.deserialize = &TagRegistry::DoDeserialize<T>;
+  vec->push_back (info);
+  uint32_t uid = vec->size ();
+  return uid;
+}
+
+} // namespace ns3
+
+#endif /* TAG_REGISTRY_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/tag.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,126 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 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
+ * 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 TAG_H
+#define TAG_H
+
+#include <stdint.h>
+#include <string>
+
+/**
+ * \relates ns3::Tag
+ * \brief this macro should be instantiated exactly once for each
+ *        new type of Tag
+ *
+ * This macro will ensure that your new Tag type is registered
+ * within the tag registry. In most cases, this macro
+ * is not really needed but, for safety, please, use it all the
+ * time.
+ *
+ * Note: This macro is _absolutely_ needed if you try to run a
+ * distributed simulation.
+ */
+#define NS_TAG_ENSURE_REGISTERED(x)	       \
+static class thisisaveryverylongclassname ##x  \
+{					       \
+ public:				       \
+  thisisaveryverylongclassname ##x ()          \
+    { uint32_t uid; uid = x::GetUid ();}       \
+} g_thisisanotherveryveryverylongname ## x;
+
+namespace ns3 {
+
+/**
+ * \brief a tag can be stored in a packet.
+ *
+ * A tag is a blob of 16 bytes of data which can be stored in
+ * a packet: a packet can contain an arbitrary number of tags
+ * and these tags are considered as "on-the-side" per-packet
+ * data structures which are not taken into account when calculating
+ * the size of the payload of a packet. They exist solely as 
+ * simulation-specific objects.
+ *
+ * Tags are typically used to:
+ *   - implement per-packet cross-layer communication
+ *   - implement packet coloring: you could store a "color" tag
+ *     in a packet to mark various types of packet for
+ *     simulation analysis
+ *
+ * To create a new type of tag, you must create a subclass
+ * of the Tag base class which defines:
+ *  - a public default constructor: needed for implementation
+ *    purposes of the Packet code.
+ *  - a public copy constructor: needed to copy a tag into
+ *    a packet tag buffer when the user invokes Packet::AddTag
+ *  - a public destructor: needed to destroy the copy of a tag
+ *    stored in a packet buffer when the user invokes Packet::RemoveTag
+ *    or when the packet is destroyed and the last reference to 
+ *    a tag instance disapears.
+ *  - a public static method named GetUid: needed to uniquely
+ *    the type of each tag instance.
+ *  - a public method named Print: needed to print the content
+ *    of a tag when the user calls Packet::PrintTags
+ *  - a public method named GetSerializedSize: needed to serialize
+ *    the content of a tag to a byte buffer when a packet must
+ *    be sent from one computing node to another in a parallel 
+ *    simulation. If this method returns 0, it means that the
+ *    tag does not need to be transfered from computing node to 
+ *     computing node
+ *  - a public method named Serialize: perform the serialization
+ *    to a byte buffer upon transfer to a new computing node in a 
+ *    parallel simulation.
+ *  - a public method named Deserialize: invert the serialization
+ *    from a byte buffer after being transfered to a new computing
+ *    node in a parallel simulation.
+ *
+ * A detailed example of what these methods should look like
+ * and how they should be implemented is described in samples/main-packet-tag.cc
+ */
+class Tag
+{
+protected:
+  /**
+   * \param name the unique name of the new type of tag
+   * \returns a newly-allocated uid
+   *
+   * This method should be used by subclasses to implement
+   * their static public GetUid method.
+   */
+  template <typename T>
+  static uint32_t AllocateUid (std::string name);
+};
+
+} // namespace ns3
+
+// implementation below.
+#include "tag-registry.h"
+
+namespace ns3 {
+
+template <typename T>
+uint32_t
+Tag::AllocateUid (std::string name)
+{
+  return TagRegistry::Register<T> (name);
+}
+
+} // namespace ns3
+
+#endif /* TAG_H */
--- a/src/common/tags.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/common/tags.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -20,84 +20,10 @@
  */
 #include "tags.h"
 #include <string.h>
+#include "ns3/fatal-error.h"
 
 namespace ns3 {
 
-TagRegistry *
-TagRegistry::GetInstance (void)
-{
-  static TagRegistry registry;
-  return &registry;
-}
-
-TagRegistry::TagRegistry ()
-  : m_sorted (false)
-{}
-
-
-void 
-TagRegistry::Record (std::string uuid, PrettyPrinter prettyPrinter, Destructor destructor)
-{
-  NS_ASSERT (!m_sorted);
-  struct TagInfoItem item;
-  item.uuid = uuid;
-  item.printer = prettyPrinter;
-  item.destructor = destructor;
-  m_registry.push_back (item);
-}
-bool 
-TagRegistry::CompareItem (const struct TagInfoItem &a, const struct TagInfoItem &b)
-{
-  return a.uuid < b.uuid;
-}
-uint32_t 
-TagRegistry::LookupUid (std::string uuid)
-{
-  if (!m_sorted) 
-    {
-      std::sort (m_registry.begin (), m_registry.end (), &TagRegistry::CompareItem);
-      m_sorted = true;
-    }
-  NS_ASSERT (m_sorted);
-  uint32_t uid = 1;
-  for (TagsDataCI i = m_registry.begin (); i != m_registry.end (); i++) 
-    {
-      if (i->uuid == uuid) 
-        {
-          return uid;
-        }
-      uid++;
-    }
-  // someone asked for a uid for an unregistered uuid.
-  NS_ASSERT (!"You tried to use unregistered tag: make sure you create an instance of type TagRegistration<YouTagType>.");
-  // quiet compiler
-  return 0;
-}
-void 
-TagRegistry::PrettyPrint (uint32_t uid, uint8_t buf[Tags::SIZE], std::ostream &os)
-{
-  NS_ASSERT (uid > 0);
-  uint32_t index = uid - 1;
-  NS_ASSERT (m_registry.size () > index);
-  PrettyPrinter prettyPrinter = m_registry[index].printer;
-  if (prettyPrinter != 0) 
-    {
-      prettyPrinter (buf, os);
-    }
-}
-void 
-TagRegistry::Destruct (uint32_t uid, uint8_t buf[Tags::SIZE])
-{
-  NS_ASSERT (uid > 0);
-  uint32_t index = uid - 1;
-  NS_ASSERT (m_registry.size () > index);
-  Destructor destructor = m_registry[index].destructor;
-  NS_ASSERT (destructor != 0);
-  destructor (buf);
-}
-
-
-
 #ifdef USE_FREE_LIST
 
 struct Tags::TagData *Tags::gFree = 0;
@@ -193,13 +119,102 @@
 }
 
 void 
-Tags::PrettyPrint (std::ostream &os)
+Tags::Print (std::ostream &os, std::string separator) const
 {
   for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) 
     {
-      TagRegistry::GetInstance ()->PrettyPrint (cur->m_id, cur->m_data, os);
+      TagRegistry::Print (cur->m_id, cur->m_data, os);
+      if (cur->m_next != 0)
+        {
+          os << separator;
+        }
+    }
+}
+
+uint32_t
+Tags::GetSerializedSize (void) const
+{
+  uint32_t totalSize = 4; // reserve space for the size of the tag data.
+  for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) 
+    {
+      uint32_t size = TagRegistry::GetSerializedSize (cur->m_id, cur->m_data);
+      if (size != 0)
+        {
+          std::string uidString = TagRegistry::GetUidString (cur->m_id);
+          totalSize += 4; // for the size of the string itself.
+          totalSize += uidString.size ();
+          totalSize += size;
+        }
+    }
+  return totalSize;
+}
+
+void 
+Tags::Serialize (Buffer::Iterator i, uint32_t totalSize) const
+{
+  i.WriteU32 (totalSize);
+  for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) 
+    {
+      uint32_t size = TagRegistry::GetSerializedSize (cur->m_id, cur->m_data);
+      if (size != 0)
+        {
+          std::string uidString = TagRegistry::GetUidString (cur->m_id);
+          i.WriteU32 (uidString.size ());
+          uint8_t *buf = (uint8_t *)uidString.c_str ();
+          i.Write (buf, uidString.size ());
+          TagRegistry::Serialize (cur->m_id, cur->m_data, i);
+        }
     }
 }
+uint32_t
+Tags::Deserialize (Buffer::Iterator i)
+{
+  uint32_t totalSize = i.ReadU32 ();
+  uint32_t bytesRead = 4;
+  while (bytesRead < totalSize)
+    {
+      uint32_t uidStringSize = i.ReadU32 ();
+      bytesRead += 4;
+      std::string uidString;
+      uidString.reserve (uidStringSize);
+      for (uint32_t j = 0; j < uidStringSize; j++)
+        {
+          uint32_t c = i.ReadU8 ();
+          uidString.push_back (c);
+        }
+      bytesRead += uidStringSize;
+      uint32_t uid = TagRegistry::GetUidFromUidString (uidString);
+      struct TagData *newStart = AllocData ();
+      newStart->m_count = 1;
+      newStart->m_next = 0;
+      newStart->m_id = uid;
+      bytesRead += TagRegistry::Deserialize (uid, newStart->m_data, i);
+      newStart->m_next = m_next;
+      m_next = newStart;
+    }
+  NS_ASSERT (bytesRead == totalSize);
+  /**
+   * The process of serialization/deserialization 
+   * results in an inverted linked-list after
+   * deserialization so, we invert the linked-list
+   * in-place here.
+   * Note: the algorithm below is pretty classic
+   * but whenever I get to code it, it makes my
+   * brain hurt :)
+   */
+  struct TagData *prev = 0;
+  struct TagData *cur = m_next;
+  while (cur != 0)
+    {
+      struct TagData *next = cur->m_next;
+      cur->m_next = prev;
+      prev = cur;
+      cur = next;
+    }
+  m_next = prev;
+  return totalSize;
+}
+
 
 
 }; // namespace ns3
@@ -224,25 +239,67 @@
   virtual bool RunTests (void);
 };
 
-struct myTagA {
+class myTagA : public Tag
+{
+public:
+  static uint32_t GetUid (void) {static uint32_t uid = AllocateUid<myTagA> ("myTagA.test.nsnam.org"); return uid;}
+  void Print (std::ostream &os) const {g_a = true;}
+  uint32_t GetSerializedSize (void) const {return 1;}
+  void Serialize (Buffer::Iterator i) const {i.WriteU8 (a);}
+  uint32_t Deserialize (Buffer::Iterator i) {a = i.ReadU8 (); return 1;}
+
   uint8_t a;
 };
-struct myTagB {
+class myTagB : public Tag
+{
+public:
+  static uint32_t GetUid (void) {static uint32_t uid = AllocateUid<myTagB> ("myTagB.test.nsnam.org"); return uid;}
+  void Print (std::ostream &os) const {g_b = true;}
+  uint32_t GetSerializedSize (void) const {return 4;}
+  void Serialize (Buffer::Iterator i) const {i.WriteU32 (b);}
+  uint32_t Deserialize (Buffer::Iterator i) {b = i.ReadU32 (); return 4;}
+
   uint32_t b;
 };
-struct myTagC {
+class myTagC : public Tag
+{
+public:
+  static uint32_t GetUid (void) {static uint32_t uid = AllocateUid<myTagC> ("myTagC.test.nsnam.org"); return uid;}
+  void Print (std::ostream &os) const {g_c = true;}
+  uint32_t GetSerializedSize (void) const {return Tags::SIZE;}
+  void Serialize (Buffer::Iterator i) const {i.Write (c, Tags::SIZE);}
+  uint32_t Deserialize (Buffer::Iterator i) {i.Read (c, Tags::SIZE); return Tags::SIZE;}
   uint8_t c [Tags::SIZE];
 };
-struct myInvalidTag {
+class myInvalidTag : public Tag
+{
+public:
+  static uint32_t GetUid (void) 
+  {static uint32_t uid = AllocateUid<myInvalidTag> ("myinvalidTag.test.nsnam.org"); return uid;}
+  void Print (std::ostream &os) const {}
+  uint32_t GetSerializedSize (void) const {return 0;}
+  void Serialize (Buffer::Iterator i) const {}
+  uint32_t Deserialize (Buffer::Iterator i) {return 0;}
+
   uint8_t invalid [Tags::SIZE+1];
 };
-struct myTagZ {
+class myTagZ  : public Tag
+{
+public:
+  static uint32_t GetUid (void) {static uint32_t uid = AllocateUid<myTagZ> ("myTagZ.test.nsnam.org"); return uid;}
+  void Print (std::ostream &os) const {g_z = true;}
+  uint32_t GetSerializedSize (void) const {return 0;}
+  void Serialize (Buffer::Iterator i) const {}
+  uint32_t Deserialize (Buffer::Iterator i) {return 0;}
+
   uint8_t z;
 };
 
-class MySmartTag 
+class MySmartTag : public Tag
 {
 public:
+  static uint32_t GetUid (void) 
+  {static uint32_t uid = AllocateUid<MySmartTag> ("MySmartTag.test.nsnam.org"); return uid;}
   MySmartTag ()
   {
     //std::cout << "construct" << std::endl;
@@ -260,43 +317,12 @@
     //std::cout << "assign" << std::endl;
     return *this;
   }
-  static void PrettyPrinterCb (const MySmartTag *a, std::ostream &os)
-  {}
+  void Print (std::ostream &os) const {}
+  uint32_t GetSerializedSize (void) const {return 0;}
+  void Serialize (Buffer::Iterator i) const {}
+  uint32_t Deserialize (Buffer::Iterator i) {return 0;}
 };
 
-static void 
-myTagAPrettyPrinterCb (struct myTagA const*a, std::ostream &os)
-{
-  //os << "struct myTagA, a="<<(uint32_t)a->a<<std::endl;
-  g_a = true;
-}
-static void 
-myTagBPrettyPrinterCb (struct myTagB const*b, std::ostream &os)
-{
-  //os << "struct myTagB, b="<<b->b<<std::endl;
-  g_b = true;
-}
-static void 
-myTagCPrettyPrinterCb (struct myTagC const*c, std::ostream &os)
-{
-  //os << "struct myTagC, c="<<(uint32_t)c->c[0]<<std::endl;
-  g_c = true;
-}
-static void 
-myTagZPrettyPrinterCb (struct myTagZ const*z, std::ostream &os)
-{
-  //os << "struct myTagZ" << std::endl;
-  g_z = true;
-}
-
-
-static TagRegistration<struct myTagA> gMyTagARegistration ("A", &myTagAPrettyPrinterCb);
-static TagRegistration<struct myTagB> gMyTagBRegistration ("B", &myTagBPrettyPrinterCb);
-static TagRegistration<struct myTagC> gMyTagCRegistration ("C", &myTagCPrettyPrinterCb);
-static TagRegistration<struct myTagZ> g_myTagZRegistration ("ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ", 
-                                                            &myTagZPrettyPrinterCb);
-static TagRegistration<MySmartTag> g_myTagSmartRegistration ("SmartTag", &MySmartTag::PrettyPrinterCb);
-
 
 TagsTest::TagsTest ()
   : Test ("Tags")
@@ -311,7 +337,7 @@
 
   // build initial tag.
   Tags tags;
-  struct myTagA a;
+  myTagA a;
   a.a = 10;
   tags.Add (a);
   a.a = 0;
@@ -321,12 +347,12 @@
       ok = false;
     }
   g_a = false;
-  tags.PrettyPrint (std::cout);
+  tags.Print (std::cout, "");
   if (!g_a)
     {
       ok = false;
     }
-  struct myTagB b;
+  myTagB b;
   b.b = 0xff;
   tags.Add (b);
   b.b = 0;
@@ -337,7 +363,7 @@
     }
   g_b = false;
   g_a = false;
-  tags.PrettyPrint (std::cout);
+  tags.Print (std::cout, "");
   if (!g_a || !g_b)
     {
       ok = false;
@@ -346,26 +372,26 @@
   Tags other = tags;
   g_b = false;
   g_a = false;
-  other.PrettyPrint (std::cout);
+  other.Print (std::cout, "");
   if (!g_a || !g_b)
     {
       ok = false;
     }
   g_b = false;
   g_a = false;
-  tags.PrettyPrint (std::cout);
+  tags.Print (std::cout, "");
   if (!g_a || !g_b)
     {
       ok = false;
     }
-  struct myTagA oA;
+  myTagA oA;
   oA.a = 0;
   other.Peek (oA);
   if (oA.a != 10) 
     {
       ok = false;
     }
-  struct myTagB oB;
+  myTagB oB;
   oB.b = 1;
   other.Peek (oB);
   if (oB.b != 0xff) 
@@ -380,7 +406,7 @@
     }
   g_b = false;
   g_a = false;
-  other.PrettyPrint (std::cout);
+  other.Print (std::cout, "");
   if (g_a || !g_b)
     {
       ok = false;
@@ -401,7 +427,7 @@
 
   other = tags;
   Tags another = other;
-  struct myTagC c;
+  myTagC c;
   memset (c.c, 0x66, 16);
   another.Add (c);
   c.c[0] = 0;
@@ -421,12 +447,12 @@
   //struct myInvalidTag invalid;
   //tags.add (&invalid);
 
-  struct myTagZ tagZ;
+  myTagZ tagZ;
   Tags testLastTag;
   tagZ.z = 0;
   testLastTag.Add (tagZ);
   g_z = false;
-  testLastTag.PrettyPrint (std::cout);
+  testLastTag.Print (std::cout, "");
   if (!g_z)
     {
       ok = false;
@@ -440,6 +466,58 @@
     tmp.Remove (smartTag);
   }
 
+  {
+    Tags source;
+    myTagA aSource;
+    aSource.a = 0x66;
+    source.Add (aSource);
+    Buffer buffer;
+    uint32_t serialized = source.GetSerializedSize ();
+    buffer.AddAtStart (serialized);
+    source.Serialize (buffer.Begin (), serialized);
+    Tags dest;
+    dest.Deserialize (buffer.Begin ());
+    myTagA aDest;
+    aDest.a = 0x55;
+    dest.Peek (aDest);
+    if (aDest.a != 0x66)
+      {
+        ok = false;
+      }
+  }
+
+  {
+    Tags source;
+    myTagA aSource;
+    aSource.a = 0x66;
+    source.Add (aSource);
+    myTagZ zSource;
+    zSource.z = 0x77;
+    source.Add (zSource);
+
+    Buffer buffer;
+    uint32_t serialized = source.GetSerializedSize ();
+    buffer.AddAtStart (serialized);
+    source.Serialize (buffer.Begin (), serialized);
+    Tags dest;
+    dest.Deserialize (buffer.Begin ());
+
+    myTagA aDest;
+    aDest.a = 0x55;
+    dest.Peek (aDest);
+    if (aDest.a != 0x66)
+      {
+        ok = false;
+      }
+    myTagZ zDest;
+    zDest.z = 0x44;
+    dest.Peek (zDest);
+    if (zDest.z != 0x44)
+      {
+        ok = false;
+      }
+  }
+
   return ok;
 }
 
--- a/src/common/tags.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/common/tags.h	Fri Sep 28 11:59:46 2007 +0100
@@ -24,12 +24,10 @@
 #include <stdint.h>
 #include <ostream>
 #include <vector>
+#include "buffer.h"
 
 namespace ns3 {
 
-template <typename T>
-class TagPrettyPrinter;
-
 /**
  * \ingroup constants
  * \brief Tag maximum size
@@ -54,7 +52,10 @@
   template <typename T>
   bool Peek (T &tag) const;
 
-  void PrettyPrint (std::ostream &os);
+  void Print (std::ostream &os, std::string separator) const;
+  uint32_t GetSerializedSize (void) const;
+  void Serialize (Buffer::Iterator i, uint32_t size) const;
+  uint32_t Deserialize (Buffer::Iterator i);
 
   inline void RemoveAll (void);
 
@@ -79,161 +80,39 @@
   struct TagData *m_next;
 };
 
-/**
- * \brief pretty print packet tags
- * 
- * This class is used to register a pretty-printer
- * callback function to print in a nice user-friendly
- * way the content of the target type. To register
- * such a type, all you need to do is instantiate
- * an instance of this type as a static variable.
- */
-template <typename T>
-class TagRegistration {
-public:
-  /**
-   * \param uuid a uuid generated with uuidgen
-   * \param fn a function which can pretty-print an instance
-   *        of type T in the output stream.
-   */
-  TagRegistration<T> (std::string uuid, void(*fn) (T const*, std::ostream &));
-private:
-  static void PrettyPrinterCb (uint8_t *buf, std::ostream &os);
-  static void DestructorCb (uint8_t *buf);
-  static void(*m_prettyPrinter) (T const*, std::ostream &);
-};
-
-}; // namespace ns3
+} // namespace ns3
 
 
 
 /**************************************************************
    An implementation of the templates defined above
  *************************************************************/
+#include "tag-registry.h"
+#include "tag.h"
 #include "ns3/assert.h"
 #include <string>
 
 namespace ns3 {
 
-class TagRegistry {
-public:
-  typedef void (*PrettyPrinter) (uint8_t [Tags::SIZE], std::ostream &);
-  typedef void (*Destructor) (uint8_t [Tags::SIZE]);
-  void Record (std::string uuid, PrettyPrinter prettyPrinter, Destructor destructor);
-  /**
-   * returns a numeric integer which uniquely identifies the input string.
-   * that integer cannot be zero which is a reserved value.
-   */
-  uint32_t LookupUid (std::string uuid);
-  void PrettyPrint (uint32_t uid, uint8_t buf[Tags::SIZE], std::ostream &os);
-  void Destruct (uint32_t uid, uint8_t buf[Tags::SIZE]);
-
-  static TagRegistry *GetInstance (void);
-private:
-  TagRegistry ();
-  struct TagInfoItem
-  {
-    std::string uuid;
-    PrettyPrinter printer;
-    Destructor destructor;
-  };
-  typedef std::vector<struct TagInfoItem> TagsData;
-  typedef std::vector<struct TagInfoItem>::const_iterator TagsDataCI;
-  static bool CompareItem (const struct TagInfoItem &a, const struct TagInfoItem &b);
-  bool m_sorted;
-  TagsData m_registry;
-};
-/**
- * The TypeUid class is used to create a mapping Type --> uid
- * Note that we use a static getUuid function which contains a
- * static std::string variable rather than a simpler static
- * member std::string variable to ensure the proper order
- * of initialization when these methods are invoked
- * from the constructor of another static variable.
- */
-template <typename T>
-class TypeUid {
-public:
-  static void Record (std::string uuid);
-  static const uint32_t GetUid (void);
-private:
-  static std::string *GetUuid (void);
-  T m_realType;
-};
-
-template <typename T>
-void TypeUid<T>::Record (std::string uuid)
-{
-  *(GetUuid ()) = uuid;
-}
-
-template <typename T>
-const uint32_t TypeUid<T>::GetUid (void)
-{
-  static const uint32_t uid = TagRegistry::GetInstance ()->
-    LookupUid (*(GetUuid ()));
-  return uid;
-}
-
-template <typename T>
-std::string *TypeUid<T>::GetUuid (void)
-{
-  static std::string uuid;
-  return &uuid;
-}
-
-
-
-/**
- * Implementation of the TagRegistration registration class.
- * It records a callback with the TagRegistry
- * This callback performs type conversion before forwarding
- * the call to the user-provided function.
- */
-template <typename T>
-TagRegistration<T>::TagRegistration (std::string uuid, void (*prettyPrinter) (T const*, std::ostream &))
-{
-  NS_ASSERT (sizeof (T) <= Tags::SIZE);
-  m_prettyPrinter  = prettyPrinter;
-  TagRegistry::GetInstance ()->
-    Record (uuid, &TagRegistration<T>::PrettyPrinterCb, &TagRegistration<T>::DestructorCb);
-  TypeUid<T>::Record (uuid);
-}
-template <typename T>
-void 
-TagRegistration<T>::PrettyPrinterCb (uint8_t *buf, std::ostream &os)
-{
-  NS_ASSERT (sizeof (T) <= Tags::SIZE);
-  T *tag = reinterpret_cast<T *> (buf);
-  (*m_prettyPrinter) (tag, os);
-}
-template <typename T>
-void
-TagRegistration<T>::DestructorCb (uint8_t *buf)
-{
-  T *tag = reinterpret_cast<T *> (buf);
-  tag->~T ();
-}
-template <typename T>
-void (*TagRegistration<T>::m_prettyPrinter) (T const*, std::ostream &) = 0;
-
-
-
-
 template <typename T>
 void 
 Tags::Add (T const&tag)
 {
+  const Tag *parent;
+  // if the following assignment fails, it is because the
+  // input to this function is not a subclass of the Tag class.
+  parent = &tag;
+
   NS_ASSERT (sizeof (T) <= Tags::SIZE);
   // ensure this id was not yet added
   for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) 
     {
-      NS_ASSERT (cur->m_id != TypeUid<T>::GetUid ());
+      NS_ASSERT (cur->m_id != T::GetUid ());
     }
   struct TagData *newStart = AllocData ();
   newStart->m_count = 1;
   newStart->m_next = 0;
-  newStart->m_id = TypeUid<T>::GetUid ();
+  newStart->m_id = T::GetUid ();
   void *buf = &newStart->m_data;
   new (buf) T (tag);
   newStart->m_next = m_next;
@@ -244,18 +123,26 @@
 bool
 Tags::Remove (T &tag)
 {
+  Tag *parent;
+  // if the following assignment fails, it is because the
+  // input to this function is not a subclass of the Tag class.
+  parent = &tag;
   NS_ASSERT (sizeof (T) <= Tags::SIZE);
-  return Remove (TypeUid<T>::GetUid ());
+  return Remove (T::GetUid ());
 }
 
 template <typename T>
 bool
 Tags::Peek (T &tag) const
 {
+  Tag *parent;
+  // if the following assignment fails, it is because the
+  // input to this function is not a subclass of the Tag class.
+  parent = &tag;
   NS_ASSERT (sizeof (T) <= Tags::SIZE);
   for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) 
     {
-      if (cur->m_id == TypeUid<T>::GetUid ()) 
+      if (cur->m_id == T::GetUid ()) 
         {
           /* found tag */
           T *data = reinterpret_cast<T *> (&cur->m_data);
@@ -315,16 +202,14 @@
         }
       if (prev != 0) 
         {
-          TagRegistry::GetInstance ()->
-            Destruct (prev->m_id, prev->m_data);
+          TagRegistry::Destruct (prev->m_id, prev->m_data);
           FreeData (prev);
         }
       prev = cur;
     }
   if (prev != 0) 
     {
-      TagRegistry::GetInstance ()->
-        Destruct (prev->m_id, prev->m_data);
+      TagRegistry::Destruct (prev->m_id, prev->m_data);
       FreeData (prev);
     }
   m_next = 0;
--- a/src/common/terminal-trace-resolver.h	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
-/* -*- 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
- * 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 TERMINAL_TRACE_RESOLVER_H
-#define TERMINAL_TRACE_RESOLVER_H
-
-#include "trace-resolver.h"
-
-namespace ns3 {
-
-class TraceContext;
-
-template <typename T>
-class TerminalTraceResolver : public TraceResolver
-{
- public:
-  TerminalTraceResolver (T &traceSource, TraceContext const &context);
- private:
-  virtual void DoConnect (CallbackBase const &cb);
-  virtual void DoDisconnect (CallbackBase const &cb);
-  T &m_traceSource;
-};
-
-}//namespace ns3
-
-namespace ns3 {
-
-template <typename T>
-TerminalTraceResolver<T>::TerminalTraceResolver (T &traceSource, 
-						 TraceContext const &context)
-  : TraceResolver (context),
-    m_traceSource (traceSource)
-{}
-template <typename T>
-void 
-TerminalTraceResolver<T>::DoConnect (CallbackBase const &cb)
-{
-  m_traceSource.AddCallback (cb, GetContext ());
-}
-template <typename T>
-void 
-TerminalTraceResolver<T>::DoDisconnect (CallbackBase const &cb)
-{
-  m_traceSource.RemoveCallback (cb);
-}
-
-}//namespace ns3
-
-#endif /* TERMINAL_TRACE_RESOLVER_H */
--- a/src/common/trace-context.cc	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,320 +0,0 @@
-/* -*- 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
- * 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 "trace-context.h"
-#include "ns3/assert.h"
-
-namespace ns3 {
-
-std::vector<uint8_t> TraceContext::m_sizes;
-
-TraceContext::TraceContext ()
-  : m_data (0)
-{}
-TraceContext::TraceContext (TraceContext const &o)
-  : m_data (o.m_data)
-{
-  if (m_data != 0)
-    {
-      m_data->count++;
-    }
-}
-TraceContext const & 
-TraceContext::operator = (TraceContext const &o)
-{
-  if (m_data != 0)
-    {
-      m_data->count--;
-      if (m_data->count == 0)
-        {
-          uint8_t *buffer = (uint8_t *)m_data;
-          delete [] buffer;
-        }
-    }
-  m_data = o.m_data;
-  if (m_data != 0)
-    {
-      m_data->count++;
-    }
-  return *this;
-}
-TraceContext::~TraceContext ()
-{
-  if (m_data != 0)
-    {
-      m_data->count--;
-      if (m_data->count == 0)
-        {
-          uint8_t *buffer = (uint8_t *)m_data;
-          delete [] buffer;
-        }
-    }
-}
-
-uint8_t 
-TraceContext::GetSize (uint8_t uid)
-{
-  return m_sizes[uid];
-}
-
-void 
-TraceContext::Add (TraceContext const &o)
-{
-  if (o.m_data == 0)
-    {
-      return;
-    }
-  uint8_t currentUid;
-  uint16_t i = 0;
-  while (i < o.m_data->size) 
-    {
-      currentUid = o.m_data->data[i];
-      uint8_t size = TraceContext::GetSize (currentUid);
-      uint8_t *selfBuffer = CheckPresent (currentUid);
-      uint8_t *otherBuffer = &(o.m_data->data[i+1]);
-      if (selfBuffer != 0)
-        {
-          if (memcmp (selfBuffer, otherBuffer, size) != 0)
-            {
-              NS_FATAL_ERROR ("You cannot add TraceContexts which "<<
-                              "have different values stored in them.");
-            }
-        }
-      else
-        {
-          DoAdd (currentUid, otherBuffer);
-        }
-      i += 1 + size;
-    }
-}
-
-uint8_t *
-TraceContext::CheckPresent (uint8_t uid) const
-{
-  if (m_data == 0)
-    {
-      return false;
-    }
-  uint8_t currentUid;
-  uint16_t i = 0;
-  do {
-    currentUid = m_data->data[i];
-    uint8_t size = TraceContext::GetSize (currentUid);
-    if (currentUid == uid)
-      {
-        return &m_data->data[i+1];
-      }
-    i += 1 + size;
-  } while (i < m_data->size && currentUid != 0);
-  return 0;
-}
-
-
-bool
-TraceContext::DoAdd (uint8_t uid, uint8_t const *buffer)
-{
-  NS_ASSERT (uid != 0);
-  uint8_t size = TraceContext::GetSize (uid);
-  uint8_t *present = CheckPresent (uid);
-  if (present != 0) {
-    if (memcmp (present, buffer, size) == 0)
-      {
-        return true;
-      }
-    else
-      {
-        return false;
-      }
-  }
-  if (m_data == 0)
-    {
-      uint16_t newSize = 1 + size;
-      uint16_t allocatedSize;
-      if (newSize > 4)
-        {
-          allocatedSize = sizeof (struct Data) + newSize - 4;
-        }
-      else
-        {
-          allocatedSize = sizeof (struct Data);
-        }
-      struct Data *data = (struct Data *) (new uint8_t [allocatedSize] ());
-      data->size = newSize;
-      data->count = 1;
-      data->data[0] = uid;
-      memcpy (data->data + 1, buffer, size);
-      m_data = data;
-    }
-  else
-    {
-      uint16_t newSize = m_data->size + 1 + size;
-      uint16_t allocatedSize;
-      if (newSize > 4)
-        {
-          allocatedSize = sizeof (struct Data) + newSize - 4;
-        }
-      else
-        {
-          allocatedSize = sizeof (struct Data);
-        }
-      struct Data *data = (struct Data *) (new uint8_t [allocatedSize] ());
-      data->size = newSize;
-      data->count = 1;
-      memcpy (data->data, m_data->data, m_data->size);
-      data->data[m_data->size] = uid;
-      memcpy (data->data + m_data->size + 1, buffer, size);
-      m_data->count--;
-      if (m_data->count == 0)
-        {
-          uint8_t *buffer = (uint8_t *)m_data;
-          delete [] buffer;
-        }
-      m_data = data;
-    }
-  return true;
-}
-bool
-TraceContext::DoGet (uint8_t uid, uint8_t *buffer) const
-{
-  if (m_data == 0)
-    {
-      return false;
-    }
-  uint8_t currentUid;
-  uint16_t i = 0;
-  do {
-    currentUid = m_data->data[i];
-    uint8_t size = TraceContext::GetSize (currentUid);
-    if (currentUid == uid)
-      {
-        memcpy (buffer, &m_data->data[i+1], size);
-        return true;
-      }
-    i += 1 + size;
-  } while (i < m_data->size && currentUid != 0);
-  return false;
-}
-
-uint8_t
-TraceContext::DoGetNextUid (void)
-{
-  static uint8_t uid = 0;
-  if (uid == 0)
-    {
-      m_sizes.push_back (0);
-    }
-  uid++;
-  return uid;
-}
-
-
-}//namespace ns3
-
-#include "ns3/test.h"
-
-namespace ns3 {
-
-template <int N>
-class Ctx
-{
-public:
-  Ctx () : m_v (0) {}
-  Ctx (int v) : m_v (v) {}
-  int Get (void) const { return N;}
-private:
-  int m_v;
-};
-
-class TraceContextTest : public Test
-{
-public:
-  TraceContextTest ();
-  virtual bool RunTests (void);
-};
-
-TraceContextTest::TraceContextTest ()
-  : Test ("TraceContext")
-{}
-bool 
-TraceContextTest::RunTests (void)
-{
-  bool ok = true;
-
-  TraceContext ctx;
-  Ctx<0> v0;
-  Ctx<0> v01 = Ctx<0> (1);
-  Ctx<1> v1;
-  Ctx<2> v2;
-  Ctx<3> v3;
-
-  if (ctx.SafeGet (v0))
-    {
-      ok = false;
-    }
-  ctx.Add (v0);
-  ctx.Add (v0);
-  if (ctx.SafeAdd (v01))
-    {
-      ok = false;
-    }
-  ctx.Get (v0);
-  ctx.Add (v1);
-  ctx.Get (v1);
-  ctx.Get (v0);
-  ctx.Get (v1);
-
-  TraceContext copy = ctx;
-  ctx.Get (v0);
-  ctx.Get (v1);
-  copy.Get (v0);
-  copy.Get (v1);
-  copy.Add (v2);
-  copy.Get (v0);
-  copy.Get (v1);
-  copy.Get (v2);
-  ctx.Add (v3);
-  ctx.Get (v0);
-  ctx.Get (v1);
-  ctx.Get (v3);
-
-  if (ctx.SafeGet (v2))
-    {
-      ok = false;
-    }
-  if (copy.SafeGet (v3))
-    {
-      ok = false;
-    }
-  ctx.Add (copy);
-  ctx.Get (v2);
-  if (copy.SafeGet (v3))
-    {
-      ok = false;
-    }
-  copy.Add (ctx);
-  copy.Get (v3);  
-  
-  return ok;
-}
-
-static TraceContextTest g_traceContextTest;
-
-
-}//namespace ns3
--- a/src/common/trace-context.h	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,167 +0,0 @@
-/* -*- 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
- * 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 TRACE_CONTEXT_H
-#define TRACE_CONTEXT_H
-
-#include <stdint.h>
-#include <vector>
-#include "ns3/fatal-error.h"
-
-namespace ns3 {
-
-/**
- * \brief Provide context to trace sources
- * \ingroup lowleveltracing
- *
- * Instances of this class are used to hold context
- * for each trace source. Each instance holds a list of
- * 'contexts'. Trace sinks can lookup these contexts
- * from this list with the ns3::TraceContext::Get method.
- *
- * This class is implemented
- * using Copy On Write which means that copying unmodified
- * versions of this class is very cheap. However, modifying
- * the content of this class through a call 
- * to ns3::TraceContext::Add will trigger a costly memory
- * reallocation if needed.
- */
-class TraceContext
-{
-public:
-  TraceContext ();
-  TraceContext (TraceContext const &o);
-  TraceContext const & operator = (TraceContext const &o);
-  ~TraceContext ();
-
-  /**
-   * \param context add context to list of trace contexts.
-   */
-  template <typename T>
-  void Add (T const &context);
-
-  /**
-   * \param o the other context
-   *
-   * Perform the Union operation (in the sense of set theory) on the
-   * two input lists of elements. This method is used in the
-   * ns3::CallbackTraceSourceSource class when multiple sinks are connected
-   * to a single source to ensure that the source does not need
-   * to store a single TraceContext instance per connected sink.
-   * Instead, all sinks share the same TraceContext.
-   */
-  void Add (TraceContext const &o);
-
-  /**
-   * \param context context to get from this list of trace contexts.
-   *
-   * This method cannot fail. If the requested trace context is not
-   * stored in this TraceContext, then, the program will halt.
-   */
-  template <typename T>
-  void Get (T &context) const;
-private:
-  friend class TraceContextTest;
-  // used exclusively for testing code.
-  template <typename T>
-  bool SafeGet (T &context) const;
-  template <typename T>
-  bool SafeAdd (T &context);
-
-  template <typename T>
-  static uint8_t GetUid (void);
-  template <typename T>
-  static uint8_t GetNextUid (void);
-  static uint8_t DoGetNextUid (void);
-  static uint8_t GetSize (uint8_t uid);
-  uint8_t *CheckPresent (uint8_t uid) const;
-  bool DoAdd (uint8_t uid, uint8_t const *buffer);
-  bool DoGet (uint8_t uid, uint8_t *buffer) const;
-
-  static std::vector<uint8_t> m_sizes;
-  struct Data {
-    uint16_t count;
-    uint16_t size;
-    uint8_t data[4];
-  } * m_data;
-};
-
-}//namespace ns3
-
-namespace ns3 {
-
-template <typename T>
-void 
-TraceContext::Add (T const &context)
-{
-  uint8_t *data = (uint8_t *) &context;
-  bool ok = DoAdd (TraceContext::GetUid<T> (), data);
-  if (!ok)
-    {
-      NS_FATAL_ERROR ("Trying to add twice the same type with different values is invalid.");
-    }
-}
-template <typename T>
-void
-TraceContext::Get (T &context) const
-{
-  uint8_t *data = (uint8_t *) &context;
-  bool found = DoGet (TraceContext::GetUid<T> (), data);
-  if (!found)
-    {
-      NS_FATAL_ERROR ("Type not stored in TraceContext");
-    }
-}
-template <typename T>
-bool
-TraceContext::SafeGet (T &context) const
-{
-  uint8_t *data = (uint8_t *) &context;
-  bool found = DoGet (TraceContext::GetUid<T> (), data);
-  return found;
-}
-template <typename T>
-bool
-TraceContext::SafeAdd (T &context)
-{
-  uint8_t *data = (uint8_t *) &context;
-  bool ok = DoAdd (TraceContext::GetUid<T> (), data);
-  return ok;
-}
-template <typename T>
-uint8_t
-TraceContext::GetUid (void)
-{
-  static uint8_t uid = GetNextUid<T> ();
-  return uid;
-}
-
-template <typename T>
-uint8_t
-TraceContext::GetNextUid (void)
-{
-  uint8_t uid = DoGetNextUid ();
-  m_sizes.push_back (sizeof (T));
-  return uid;
-}
-
-}//namespace ns3
-
-#endif /* TRACE_CONTEXT_H */
--- a/src/common/trace-resolver.cc	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,104 +0,0 @@
-/* -*- 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
- * 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 "trace-resolver.h"
-
-namespace ns3 {
-
-TraceResolver::TraceResolver (TraceContext const &context)
-  : m_context (context)
-{}
-
-TraceResolver::~TraceResolver ()
-{}
-
-TraceContext const &
-TraceResolver::GetContext (void) const
-{
-  return m_context;
-}
-
-void 
-TraceResolver::Connect (std::string path, CallbackBase const &cb)
-{
-  std::string::size_type cur = 1;
-  // check that first char is "/"
-  std::string::size_type next = path.find ("/", cur);
-  std::string element = std::string (path, cur, next-1);
-  TraceResolverList resolverList = DoLookup (element);
-  for (TraceResolverList::iterator i = resolverList.begin (); i != resolverList.end (); i++)
-    {
-      TraceResolver *resolver = *i;
-      if (next == std::string::npos) 
-	{
-	  // we really break the recursion here.
-	  resolver->DoConnect (cb);
-	}
-      else
-	{
-	  std::string subpath = std::string (path, next, std::string::npos);
-          resolver->Connect (subpath, cb);
-	}
-      delete resolver;
-    }
-  resolverList.erase (resolverList.begin (), resolverList.end ());
-}
-
-void 
-TraceResolver::Disconnect (std::string path, CallbackBase const &cb)
-{
-  std::string::size_type cur = 1;
-  // check that first char is "/"
-  std::string::size_type next = path.find ("/", cur);
-  std::string element = std::string (path, cur, next-1);
-  TraceResolverList resolverList = DoLookup (element);
-  for (TraceResolverList::iterator i = resolverList.begin (); i != resolverList.end (); i++)
-    {
-      TraceResolver *resolver = *i;
-      if (next == std::string::npos) 
-	{
-	  // we really break the recursion here.
-	  resolver->DoDisconnect (cb);
-	}
-      else
-	{
-	  std::string subpath = std::string (path, next, std::string::npos);
-          resolver->Disconnect (subpath, cb);
-	}
-      delete resolver;
-    }
-  resolverList.erase (resolverList.begin (), resolverList.end ());
-}
-
-TraceResolver::TraceResolverList 
-TraceResolver::DoLookup (std::string id) const
-{
-  return TraceResolverList ();
-}
-void 
-TraceResolver::DoConnect (CallbackBase const &cb)
-{}
-
-void 
-TraceResolver::DoDisconnect (CallbackBase const &cb)
-{}
-
-
-}//namespace ns3
--- a/src/common/trace-resolver.h	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,119 +0,0 @@
-/* -*- 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
- * 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 TRACE_RESOLVER_H
-#define TRACE_RESOLVER_H
-
-#include <string>
-#include <list>
-#include "trace-context.h"
-
-namespace ns3 {
-
-class CallbackBase;
-
-/**
- * \brief the base class which is used to incremental perform trace
- *        namespace resolution.
- * \ingroup lowleveltracing
- *
- * This class provides a public API to the ns3::TraceRoot object:
- *   - ns3::TraceResolver::Connect
- *   - ns3::TraceResolver::Disconnect
- *
- * It also provides an API for its subclasses. Each subclass should 
- * implement one of:
- *   - ns3::TraceResolver::DoLookup
- *   - ns3::TraceResolver::DoConnect and ns3::TraceResolver::DoDisconnect
- * Each subclass must also provide an ns3::TraceContext to the TraceResolver
- * constructor. Finally, each subclass can access the ns3::TraceContext 
- * associated to this  ns3::TraceResolver through the 
- * ns3::TraceResolver::GetContext method.
- */
-class TraceResolver
-{
-public:
-  virtual ~TraceResolver ();
-  /**
-   * \param path the namespace path to resolver
-   * \param cb the callback to connect to the matching namespace
-   *
-   * This method is typically invoked by ns3::TraceRoot but advanced
-   * users could also conceivably call it directly if they want to
-   * skip the ns3::TraceRoot.
-   */
-  void Connect (std::string path, CallbackBase const &cb);
-  /**
-   * \param path the namespace path to resolver
-   * \param cb the callback to disconnect in the matching namespace
-   *
-   * This method is typically invoked by ns3::TraceRoot but advanced
-   * users could also conceivably call it directly if they want to
-   * skip the ns3::TraceRoot.
-   */
-  void Disconnect (std::string path, CallbackBase const &cb);
-protected:
-  /**
-   * \param context the context used to initialize this TraceResolver.
-   *
-   * Every subclass must call this constructor
-   */
-  TraceResolver (TraceContext const &context);
-  /**
-   * \returns the ns3::TraceContext stored in this ns3::TraceResolver.
-   *
-   * Subclasses usually invoke this method to get access to the
-   * TraceContext stored here to pass it down to the TraceResolver
-   * constructors invoked from within the DoLookup method.
-   */
-  TraceContext const &GetContext (void) const;
-  typedef std::list<TraceResolver *> TraceResolverList;
-private:
-  TraceResolver ();
-  /**
-   * \param id the id to resolve. This is supposed to be
-   * one element of the global tracing namespace.
-   * \returns a list of reslvers which match the input namespace element
-   *
-   * A subclass which overrides this method should return a potentially
-   * empty list of pointers to ns3::TraceResolver instances which match
-   * the input namespace element. Each of these TraceResolver should be
-   * instanciated with a TraceContext which holds enough context
-   * information to identify the type of the TraceResolver.
-   */
-  virtual TraceResolverList DoLookup (std::string id) const;
-  /**
-   * \param cb callback to connect
-   *
-   * This method is invoked on leaf trace resolvers.
-   */
-  virtual void DoConnect (CallbackBase const &cb);
-  /**
-   * \param cb callback to disconnect
-   *
-   * This method is invoked on leaf trace resolvers.
-   */
-  virtual void DoDisconnect (CallbackBase const &cb);
-  TraceContext m_context;
-};
-
-}//namespace ns3
-
-#endif /* TRACE_RESOLVER_H */
--- a/src/common/trace-root.cc	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-/* -*- 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
- * 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 "trace-root.h"
-#include "ns3/composite-trace-resolver.h"
-#include "ns3/trace-context.h"
-
-namespace ns3 {
-
-void 
-TraceRoot::Connect (std::string path, CallbackBase const &cb)
-{
-  TraceResolver *resolver = GetComposite ();
-  resolver->Connect (path, cb);
-}
-void 
-TraceRoot::Disconnect (std::string path, CallbackBase const &cb)
-{
-  TraceResolver *resolver = GetComposite ();
-  resolver->Disconnect (path, cb);
-}
-void 
-TraceRoot::Register (std::string name, 
-                     Callback<TraceResolver *,TraceContext const &> createResolver)
-{
-  CompositeTraceResolver *resolver = GetComposite ();
-  resolver->Add (name, createResolver, TraceRoot::NOTHING);
-}
-
-CompositeTraceResolver *
-TraceRoot::GetComposite (void)
-{
-  static CompositeTraceResolver resolver = CompositeTraceResolver (TraceContext ());
-  return &resolver;
-}
-
-} // namespace ns3
--- a/src/common/trace-root.h	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,338 +0,0 @@
-/* -*- 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
- * 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 TRACE_ROOT_H
-#define TRACE_ROOT_H
-
-#include <string>
-#include "ns3/callback.h"
-
-/**
- * \defgroup lowleveltracing Low-level tracing
- *
- * This low-level API is built around a few concepts:
- *   - There can be any number of trace source objects. Each trace source
- *     object can generate any number of trace events. The current
- *     trace source objects are: ns3::CallbackTraceSourceSource, ns3::UVTraceSource,
- *     ns3::SVTraceSource, and, ns3::FVTraceSource.
- *   - Each trace source can be connected to any number of trace sinks.
- *     A trace sink is a ns3::Callback with a very special signature. Its
- *     first argument is always a ns3::TraceContext.
- *   - Every trace source is uniquely identified by a ns3::TraceContext. Every
- *     trace sink can query a ns3::TraceContext for information. This allows
- *     a trace sink which is connected to multiple trace sources to identify
- *     from which source each event is coming from.
- *
- * To define new trace sources, a model author needs to instante one trace source
- * object for each kind of tracing event he wants to export. The trace source objects
- * currently defined are:
- *  - ns3::CallbackTraceSourceSource: this trace source can be used to convey any kind of 
- *    trace event to the user. It is a functor, that is, it is a variable
- *    which behaves like a function which will forward every event to every
- *    connected trace sink (i.e., ns3::Callback). This trace source takes
- *    up to four arguments and forwards these 4 arguments together with the
- *    ns3::TraceContext which identifies this trace source to the connected
- *    trace sinks.
- *  - ns3::UVTraceSource: this trace source is used to convey key state variable
- *    changes to the user. It behaves like a normal integer unsigned variable:
- *    you can apply every normal arithmetic operator to it. It will forward
- *    every change in the value of the variable back to every connected trace 
- *    sink by providing a TraceContext, the old value and the new value.
- *  - ns3::SVTraceSource: this is the signed integer equivalent of 
- *    ns3::UVTraceSource.
- *  - ns3::FVTraceSource: this is the floating point equivalent of 
- *    ns3::UVTraceSource and ns3::SVTraceSource.
- *
- * For example, to define a trace source which notifies you of a new packet
- * being transmitted, you would have to:
- * \code
- * class MyModel
- * {
- *  public:
- *   void Tx (Packet const &p);
- *  private:
- *   CallbackTraceSource<Packet const &> m_txTrace;
- * };
- *
- * void
- * MyModel::Tx (Packet const &p)
- * {
- *   // trace packet tx event.
- *   m_txTrace (p);
- *   // ... send the packet for real.
- * }
- * \endcode
- *
- * Once the model author has instantiated these objects and has wired them 
- * in his simulation code (that is, he calls them wherever he wants to trigger 
- * a trace event), he needs to make these trace sources available to users
- * to allow them to connect any number of trace sources to any number
- * of user trace sinks. While it would be possible to make each model
- * export directly each of his trace source instances and request users to
- * invoke a source->Connect (callback) method to perform the connection
- * explicitely, it was felt that this was a bit cumbersome to do.
- *
- * As such, the ``connection'' between a set of sources and a sink is 
- * performed through a third-party class, the TraceResolver, which
- * can be used to automate the connection of multiple matching trace sources
- * to a single sink. This TraceResolver works by defining a hierarchical 
- * tracing namespace: the root of this namespace is accessed through the 
- * ns3::TraceRoot class. The namespace is represented as a string made of 
- * multiple elements, each of which is separated from the other elements 
- * by the '/' character. A namespace string always starts with a '/'.
- * 
- * By default, the current simulation models provide a '/nodes' tracing root. 
- * This '/nodes' namespace is structured as follows:
- * \code
- *  /nodes/n/arp
- *  /nodes/n/udp
- *  /nodes/n/ipv4
- *               /tx
- *               /rx
- *               /drop
- *               /interfaces/n/netdevice
- *                                      /queue/
- *                                            /enque
- *                                            /deque
- *                                            /drop
- * \endcode
- *
- * The 'n' element which follows the /nodes and /interfaces namespace elements
- * identify a specific node and interface through their index within the 
- * ns3::NodeList and ns3::Ipv4 objects respectively.
- *
- * To connect a trace sink to a trace source identified by a namespace string,
- * a user can call the ns3::TraceRoot::Connect method (the ns3::TraceRoot::Disconnect
- * method does the symmetric operation). This connection method can accept
- * fully-detailed namespace strings but it can also perform pattern matching
- * on the user-provided namespace strings to connect multiple trace sources
- * to a single trace sink in a single connection operation.
- *
- * The syntax of the pattern matching rules are loosely based on regular 
- * expressions:
- *   - the '*' character matches every element
- *   - the (a|b) construct matches element 'a' or 'b'
- *   - the [ss-ee] construct matches all numerical values which belong
- *     to the interval which includes ss and ee
- *
- * For example, the user could use the following to connect a single sink
- * to the ipv4 tx, rx, and drop trace events:
- *
- * \code
- * void MyTraceSink (TraceContext const &context, Packet &packet);
- * TraceRoot::Connect ("/nodes/ * /ipv4/ *", MakeCallback (&MyTraceSink));
- * \endcode
- *
- * Of course, this code would work only if the signature of the trace sink
- * is exactly equal to the signature of all the trace sources which match
- * the namespace string (if one of the matching trace source does not match
- * exactly, a fatal error will be triggered at runtime during the connection
- * process). The ns3::TraceContext extra argument contains
- * information on where the trace source is located in the namespace tree.
- * In that example, if there are multiple nodes in this scenario, each
- * call to the MyTraceSink function would receive a different TraceContext,
- * each of which would contain a different NodeList::Index object.
- *
- * It is important to understand exactly what an ns3::TraceContext
- * is. It is a container for a number of type instances. Each instance of
- * a ns3::TraceContext contains one and only one instance of a given type.
- * ns3::TraceContext::Add can be called to add a type instance into a 
- * TraceContext instance and ns3::TraceContext::Get can be called to get
- * a copy of a type instance stored into the ns3::TraceContext. If ::Get
- * cannot retrieve the requested type, a fatal error is triggered at
- * runtime. The values stored into an ns3::TraceContext attached to a 
- * trace source are automatically determined during the namespace
- * resolution process. To retrieve a value from a ns3::TraceContext, the
- * code can be as simple as this:
- * \code
- * void MyTraceSink (TraceContext const &context, Packet &packet)
- * {
- *   NodeList::Index index;
- *   context.Get (index);
- *   std::cout << "node id=" << NodeList::GetNode (index)->GetId () << std::endl;
- * }
- * \endcode
- *
- * The hierarchical global namespace described here is not implemented
- * in a single central location: it was felt that doing this would make
- * it too hard to introduce user-specific models which could hook
- * automatically into the overal tracing system. If the tracing
- * namespace was implemented in a single central location, every model
- * author would have had to modify this central component to make
- * his own model available to trace users.
- *
- * Instead, the handling of the namespace is distributed across every relevant
- * model: every model implements only the part of the namespace it is
- * really responsible for. To do this, every model is expected
- * to provide an instance of a TraceResolver whose
- * responsability is to recursively provide access to the trace sources
- * defined in its model. Each TraceResolver instance should be a subclass
- * of the TraceResolver base class which implements either the DoLookup
- * or the DoConnect and DoDisconnect methods. Because implementing these
- * methods can be a bit tedious, our tracing framework provides a number 
- * of helper template classes which should save the model author from 
- * having to implement his own in most cases:
- *    - ns3::CompositeTraceResolver: this subclass of ns3::TraceResolver can 
- *      be used to aggregate together multiple trace sources and multiple other 
- *      ns3::TraceResolver instances.
- *    - ns3::ArrayTraceResolver: this subclass of ns3::TraceResolver can be 
- *      used to match any number of elements within an array where every element 
- *      is identified by its index.
- *
- * Once you can instantiate your own ns3::TraceResolver object instance, you 
- * have to hook it up into the global namespace. There are two ways to do this:
- *   - you can hook your ns3::TraceResolver creation method as a new trace 
- *     root by using the ns3::TraceRoot::Register method
- *   - you can hook your new ns3::TraceResolver creation method into the 
- *     container of your model. This step will obvsiouly depend on which model
- *     contains your own model but, if you wrote a new l3 protocol, all you
- *     would have to do to hook into your container L3Demux class is to implement 
- *     the pure virtual method inherited from the L3Protocol class whose name is 
- *     ns3::L3protocol::CreateTraceResolver.
- *
- * So, in most cases, exporting a model's trace sources is a matter of 
- * implementing a method CreateTraceResolver as shown below:
- * \code
- * class MyModel
- * {
- * public:
- *   enum TraceType {
- *    TX,
- *    RX,
- *    ...
- *   };
- *   TraceResolver *CreateTraceResolver (TraceContext const &context);
- *   void Tx (Packet const &p);
- * private:
- *   CallbackTraceSource<Packet const &> m_txTrace;
- * };
- *
- * TraceResolver *
- * MyModel::CreateTraceResolver (TraceContext const &context)
- * {
- *   CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
- *   resolver->Add ("tx", m_txTrace, MyModel::TX);
- *   return resolver;
- * }
- * void 
- * MyModel::Tx (Packet const &p)
- * {
- *   m_txTrace (p);
- * }
- * \endcode
- *
- * If you really want to have fun and implement your own ns3::TraceResolver 
- * subclass, you need to understand the basic Connection and Disconnection
- * algorithm. The code of that algorithm is wholy contained in the
- * ns3::TraceResolver::Connect and ns3::TraceResolver::Disconnect methods.
- * The idea is that we recursively parse the input namespace string by removing
- * the first namespace element. This element is 'resolved' is calling
- * the ns3::TraceResolver::DoLookup method which returns a list of
- * TraceResolver instances. Each of the returned TraceResolver instance is
- * then given what is left of the namespace by calling ns3::TraceResolver::Connect
- * until the last namespace element is processed. At this point, we invoke
- * the ns3::TraceResolver::DoConnect or ns3::TraceResolver::DoDisconnect 
- * methods to break the recursion. A good way to understand this algorithm
- * is to trace its behavior. Let's say that you want to connect to
- * '/nodes/ * /ipv4/interfaces/ * /netdevice/queue/ *'. It would generate
- * the following call traces:
- *
- * \code
- * TraceRoot::Connect ("/nodes/ * /ipv4/interfaces/ * /netdevice/queue/ *", callback);
- * traceContext = TraceContext ();
- * rootResolver = CompositeTraceResolver (traceContext);
- * rootResolver->Connect ("/nodes/ * /ipv4/interfaces/ * /netdevice/queue/ *", callback);
- *   resolver = CompositeTraceResolver::DoLookup ("nodes");
- *     return NodeList::CreateTraceResolver (GetContext ());
- *       return ArrayTraceResolver (context);
- *   resolver->Connect ("/ * /ipv4/interfaces/ * /netdevice/queue/ *", callback);
- *     ArrayTraceResolver::DoLookup ("*");
- *       for (i = 0; i < n_nodes; i++)
- *         resolver = nodes[i]->CreateTraceResolver (GetContext ());
- *           return CompositeTraceResolver (context);
- *         resolvers.add (resolver);
- *       return resolvers;
- *     for resolver in (resolvers)
- *       resolver->Connect ("/ipv4/interfaces/ * /netdevice/queue/ *", callback);
- *         CompositeTraceResolver::DoLookup ("ipv4");
- *           resolver = ipv4->CreateTraceResolver (GetContext ());
- *             return CompositeTraceResolver (context);
- *           return resolver;
- *         resolver->Connect ("/interfaces/ * /netdevice/queue/ *", callback);
- *           CompositeTraceResolver::DoLookup ("interfaces");
- *             resolver = ArrayTraceResolver (GetContext ());
- *           resolver->Connect ("/ * /netdevice/queue/ *", callback);
- *             ArrayTraceResolver::DoLookup ("*");
- *               for (i = 0; i < n_interfaces; i++)
- *                  resolver = interfaces[i]->CreateTraceResolver (GetContext ());
- *                    return CompositeTraceResolver ()
- *                  resolvers.add (resolver);
- *               return resolvers;
- *             resolver->Connect ("/netdevice/queue/ *", callback);
- *               CompositeTraceResolver::DoLookup ("netdevice");
- *                 resolver = NetDevice::CreateTraceResolver (GetContext ());
- *                   return CompositeTraceResolver ();
- *                 return resolver;
- *               resolver->Connect ("/queue/ *", callback);
- *                 CompositeTraceResolver::DoLookup ("queue");
- *                   resolver = Queue::CreateTraceResolver (GetContext ());
- *                     return CompositeTraceResolver ();
- *                   return resolver
- *                 resolver->Connect ("*", callback);
- *                   CompositeTraceResolver::DoLookup ("*");
- *                     for match in (matches)
- *                       resolver = TerminalTraceResolver ("match");
- *                       resolvers.add (resolver)
- *                     return resolvers;
- *                   for resolver in (resolvers)
- *                     TerminalTraceResolver->DoConnect (callback);
- * \endcode
- */
-
-namespace ns3 {
-
-class CompositeTraceResolver;
-class TraceResolver;
-class TraceContext;
-class CallbackBase;
-
-/**
- * \brief The main class used to access tracing functionality for
- * a user.
- *
- * \ingroup lowleveltracing
- */
-class TraceRoot
-{
-public:
-  static void Connect (std::string path, CallbackBase const &cb);
-  static void Disconnect (std::string path, CallbackBase const &cb);
-  static void Register (std::string name, 
-                        Callback<TraceResolver *,TraceContext const &> createResolver);
-private:
-  static CompositeTraceResolver *GetComposite (void);
-  enum TraceType {
-    NOTHING,
-  };
-};
-
-}// namespace ns3
-
-#endif /* TRACE_ROOT_H */
--- a/src/common/trailer.cc	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2005 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
- * 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 "trailer.h"
-
-namespace ns3 {
-
-Trailer::~Trailer ()
-{}
-
-}; // namespace ns3
--- a/src/common/trailer.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/common/trailer.h	Fri Sep 28 11:59:46 2007 +0100
@@ -22,7 +22,28 @@
 #ifndef TRAILER_H
 #define TRAILER_H
 
-#include "chunk.h"
+#include "chunk-registry.h"
+
+/**
+ * \relates ns3::Trailer
+ * \brief this macro should be instantiated exactly once for each
+ *        new type of Trailer
+ *
+ * This macro will ensure that your new Trailer type is registered
+ * within the packet trailer registry. In most cases, this macro
+ * is not really needed but, for safety, please, use it all the
+ * time.
+ *
+ * Note: This macro is _absolutely_ needed if you try to run a
+ * distributed simulation.
+ */
+#define NS_TRAILER_ENSURE_REGISTERED(x)          \
+static class thisisaveryverylongclassname ##x    \
+{                                                \
+ public:                                         \
+  thisisaveryverylongclassname ##x ()            \
+    { uint32_t uid; uid = x::GetUid ();}         \
+} g_thisisanotherveryveryverylongname ##x;
 
 namespace ns3 {
 
@@ -30,81 +51,66 @@
  * \brief Protocol trailer serialization and deserialization.
  *
  * Every Protocol trailer which needs to be inserted or removed
- * from a Packet instance must derive from this abstract base class
- * and implement the private pure virtual methods listed below:
- *   - ns3::Trailer::SerializeTo
- *   - ns3::Trailer::DeserializeFrom
- *   - ns3::Trailer::GetSerializedSize
- *   - ns3::Trailer::PrintTo
+ * from a Packet instance must derive from this base class and
+ * implement the following public methods:
+ *   - a default constructor: is used by the internal implementation
+ *     if the Packet class.
+ *   - a static method named GetUid: is used to uniquely identify
+ *     the type of each trailer. This method shall return a unique
+ *     integer allocated with Trailer::AllocateUid.
+ *   - a method named Serialize: is used by Packet::AddTrailer to
+ *     store a trailer into the byte buffer of a packet.
+ *     The input iterator points to the end of the byte buffer in
+ *     which the trailer should write its data: the user is thus
+ *     required to call Buffer::Iterator::Prev prior to writing
+ *     any data in the buffer. The data written is expected to 
+ *     match bit-for-bit the representation of this trailer in a 
+ *     real network.
+ *   - a method named GetSerializedSize: is used by Packet::AddTrailer
+ *     to store a trailer into the byte buffer of a packet. This method
+ *     should return the number of bytes which are needed to store
+ *     the full trailer data by Serialize.
+ *   - a method named Deserialize: is used by Packet::RemoveTrailer to
+ *     re-create a trailer from the byte buffer of a packet. The input
+ *     iterator points to the end of the byte buffer from which
+ *     the trailer should read its data: the user is thus required to
+ *     call Buffer::Iterator::Prev prior to reading any data from the
+ *     buffer. The data read is expected to match bit-for-bit the 
+ *     representation of this trailer in real networks. This method 
+ *     shall return an integer which identifies the number of bytes read.
+ *   - a method named Print: is used by Packet::Print to print the 
+ *     content of a trailer as ascii data to a c++ output stream.
+ *     Although the trailer is free to format its output as it
+ *     wishes, it is recommended to follow a few rules to integrate
+ *     with the packet pretty printer: start with flags, small field 
+ *     values located between a pair of parens. Values should be separated 
+ *     by whitespace. Follow the parens with the important fields, 
+ *     separated by whitespace.
+ *     i.e.: (field1 val1 field2 val2 field3 val3) field4 val4 field5 val5
+ *   - a method named GetName: is used by Packet::Print to print
+ *     trailer fragments. This method should return a user-readable
+ *     single word as all capitalized letters.
  *
- * Note that the SerializeTo and DeserializeFrom methods behave
- * in a way which might seem surprising to users: the input iterator
- * really points to the end of the buffer to which and from which
- * the user is expected to write and read respectively. This means that
- * if the trailer has a fixed size and if the user wishes to read or
- * write that trailer from front to back, the user must rewind the 
- * iterator by hand to go to the start of the trailer. Typical code
- * looks like this:
- * \code
- * void CrcTrailer::SerializeTo (Buffer::Iterator end)
- * {
- *   end.Prev (4);
- *   end.WriteHtonU32 (m_crc);
- * }
- * \endcode
- *
- * Some users would have expected that the iterator would be rewinded 
- * to the "start" of the trailer before calling SerializeTo and DeserializeFrom.
- * However, this behavior was not implemented because it cannot be made to
- * work reliably for trailers which have a variable size. i.e., if the trailer 
- * contains options, the code which calls DeserializeFrom cannot rewind
- * to the start of the trailer because it does not know the real size of the 
- * trailer. Hence, to make this legitimate use-case work (variable-sized 
- * trailers), the input iterator to DeserializeFrom and SerializeTo points
- * to the end of the trailer, and not its start.
  */
-class Trailer : public Chunk {
-public:
-  virtual ~Trailer ();
-private:
-  /**
-   * \param os the std output stream in which this 
-   *       protocol trailer must print itself.
-   */
-  virtual void PrintTo (std::ostream &os) const = 0;
-
-  /**
-   * \returns the size of the serialized Trailer.
-   *
-   * This method is used by Packet::AddTrailer to reserve
-   * enough room in the packet byte buffer prior to calling
-   * Trailer::Serialize.
-   */
-  virtual uint32_t GetSerializedSize (void) const = 0;
-
-  /**
-   * \param end the buffer iterator in which the protocol trailer
-   *    must serialize itself. This iterator identifies 
-   *    the end of the buffer.
-   *
-   * This iterator must be typically moved with the Buffer::Iterator::Prev
-   * method before writing any byte in the buffer.
-   */
-  virtual void SerializeTo (Buffer::Iterator end) const = 0;
-  /**
-   * \param end the buffer iterator from which the protocol trailer must
-   *    deserialize itself. This iterator identifies 
-   *    the end of the buffer.
-   * \returns the number of bytes read from the buffer
-   *
-   * This iterator must be typically moved with the Buffer::Iterator::Prev
-   * method before reading any byte in the buffer. The value returned
-   * is used to trim the packet byte buffer of the corresponding
-   * amount when this method is invoked from Packet::RemoveTrailer
-   */
-  virtual uint32_t DeserializeFrom (Buffer::Iterator end) = 0;
+class Trailer 
+{
+protected:
+  template <typename T>
+  static uint32_t AllocateUid (std::string uidString);
 };
 
-}; // namespace ns3
+} // namespace ns3
+
+namespace ns3 {
+
+template <typename T>
+uint32_t 
+Trailer::AllocateUid (std::string uidString)
+{
+  return ChunkRegistry::RegisterTrailer<T> (uidString);
+}
+
+
+} // namespace ns3
 
 #endif /* TRAILER_H */
--- a/src/common/uv-trace-source.h	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,245 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2006 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
- * 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 UV_TRACE_SOURCE_H
-#define UV_TRACE_SOURCE_H
-
-#include "callback-trace-source.h"
-#include <stdint.h>
-
-namespace ns3 {
-
-class UVTraceSourceBase {
-public:
-  typedef CallbackTraceSource<uint64_t, uint64_t> ChangeNotifyCallback;
-
-  UVTraceSourceBase ()
-      : m_callback () {}
-  /* We don't want to copy the base callback. Only setCallback on
-   * a specific instance will do something to it. */
-  UVTraceSourceBase (UVTraceSourceBase const &o) 
-      : m_callback () {}
-  UVTraceSourceBase &operator = (UVTraceSourceBase const &o) {
-      return *this;
-  }
-  ~UVTraceSourceBase () {}
-
-  void AddCallback (CallbackBase const & callback, TraceContext const & context) {
-    m_callback.AddCallback (callback, context);
-  }
-  void RemoveCallback (CallbackBase const & callback) {
-    m_callback.RemoveCallback (callback);
-  }
-
-protected:
-  void Notify (uint64_t oldVal, uint64_t newVal) {
-      if (oldVal != newVal) 
-        {
-          m_callback (oldVal, newVal);
-        }
-  }
-private:
-  ChangeNotifyCallback m_callback;
-};
-
-template <typename T>
-class SVTraceSource;
-
-
-/**
- * \brief trace variables of type "unsigned integer"
- * \ingroup lowleveltracing
- *
- * This template class implements a POD type: it
- * behaves like any other variable of type "unsigned integer"
- * except that it also reports any changes to its
- * value with its internal callback.
- *
- * To instantiate a 32-bit unsigned variable (to store
- * a TCP counter for example), you would create a variable of type
- * ns3::UVTraceSource<uint32_t> :
- \code
- #include <stdint.h>
- #include "ns3/uv-trace-source.h"
-
- ns3::UVTraceSource<uint32_t> var;
- \endcode
- * and you would use it like any other variable of type uint32_t:
- \code
- var += 12;
- var = 10;
- \endcode
- */
-template <typename T>
-class UVTraceSource : public UVTraceSourceBase {
-public:
-  UVTraceSource ()
-      : m_var ()
-  {}
-  UVTraceSource (T const &var) 
-      : m_var (var)
-  {}
-
-  UVTraceSource &operator = (UVTraceSource const &o) {
-      Assign (o.Get ());
-      return *this;
-  }
-  template <typename TT>
-  UVTraceSource &operator = (UVTraceSource<TT> const &o) {
-      Assign (o.Get ());
-      return *this;
-  }
-  template <typename TT>
-  UVTraceSource &operator = (SVTraceSource<TT> const &o) {
-      Assign (o.Get ());
-      return *this;
-  }
-  UVTraceSource &operator++ () {
-      Assign (Get () + 1);
-      return *this;
-  }
-  UVTraceSource &operator-- () {
-      Assign (Get () - 1);
-      return *this;
-  }
-  UVTraceSource operator++ (int) {
-      UVTraceSource old (*this);
-      ++*this;
-      return old;
-  }
-  UVTraceSource operator-- (int) {
-      UVTraceSource old (*this);
-      --*this;
-      return old;
-  }
-  operator T () const {
-      return Get ();
-  }
-
-
-  void Assign (T var) {
-      Notify (m_var, var);
-      m_var = var;
-  }
-  T Get (void) const {
-      return m_var;
-  }
-
-private:
-  T m_var;
-};
-
-template <typename T>
-UVTraceSource<T> &operator += (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
-  lhs.Assign (lhs.Get () + rhs.Get ());
-  return lhs;
-}
-template <typename T>
-UVTraceSource<T> &operator -= (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
-  lhs.Assign (lhs.Get () - rhs.Get ());
-  return lhs;
-}
-template <typename T>
-UVTraceSource<T> &operator *= (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
-  lhs.Assign (lhs.Get () * rhs.Get ());
-  return lhs;
-}
-template <typename T>
-UVTraceSource<T> &operator /= (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
-  lhs.Assign (lhs.Get () / rhs.Get ());
-  return lhs;
-}
-template <typename T>
-UVTraceSource<T> &operator <<= (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
-  lhs.Assign (lhs.Get () << rhs.Get ());
-  return lhs;
-}
-template <typename T>
-UVTraceSource<T> &operator >>= (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
-  lhs.Assign (lhs.Get () >> rhs.Get ());
-  return lhs;
-}
-template <typename T>
-UVTraceSource<T> &operator &= (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
-  lhs.Assign (lhs.Get () & rhs.Get ());
-  return lhs;
-}
-template <typename T>
-UVTraceSource<T> &operator |= (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
-  lhs.Assign (lhs.Get () | rhs.Get ());
-  return lhs;
-}
-template <typename T>
-UVTraceSource<T> &operator ^= (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
-  lhs.Assign (lhs.Get () ^ rhs.Get ());
-  return lhs;
-}
-
-
-template <typename T, typename U>
-UVTraceSource<T> &operator += (UVTraceSource<T> &lhs, U const &rhs) {
-  lhs.Assign (lhs.Get () + rhs);
-  return lhs;
-}
-template <typename T, typename U>
-UVTraceSource<T> &operator -= (UVTraceSource<T> &lhs, U const &rhs) {
-  lhs.Assign (lhs.Get () - rhs);
-  return lhs;
-}
-template <typename T, typename U>
-UVTraceSource<T> &operator *= (UVTraceSource<T> &lhs, U const &rhs) {
-  lhs.Assign (lhs.Get () * rhs);
-  return lhs;
-}
-template <typename T, typename U>
-UVTraceSource<T> &operator /= (UVTraceSource<T> &lhs, U const &rhs) {
-  lhs.Assign (lhs.Get () / rhs);
-  return lhs;
-}
-template <typename T, typename U>
-UVTraceSource<T> &operator <<= (UVTraceSource<T> &lhs, U const &rhs) {
-  lhs.Assign (lhs.Get () << rhs);
-  return lhs;
-}
-template <typename T, typename U>
-UVTraceSource<T> &operator >>= (UVTraceSource<T> &lhs, U const &rhs) {
-  lhs.Assign (lhs.Get () >> rhs);
-  return lhs;
-}
-template <typename T, typename U>
-UVTraceSource<T> &operator &= (UVTraceSource<T> &lhs, U const &rhs) {
-  lhs.Assign (lhs.Get () & rhs);
-  return lhs;
-}
-template <typename T, typename U>
-UVTraceSource<T> &operator |= (UVTraceSource<T> &lhs, U const &rhs) {
-  lhs.Assign (lhs.Get () | rhs);
-  return lhs;
-}
-template <typename T, typename U>
-UVTraceSource<T> &operator ^= (UVTraceSource<T> &lhs, U const &rhs) {
-  lhs.Assign (lhs.Get () ^ rhs);
-  return lhs;
-}
-
-}; // namespace ns3
-
-#endif /* UV_TRACE_SOURCE_H */
--- a/src/common/variable-tracer-test.cc	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,272 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2006 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
- * 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 "uv-trace-source.h"
-#include "sv-trace-source.h"
-#include "trace-context.h"
-#include "ns3/test.h"
-#include "ns3/callback.h"
-
-
-namespace ns3 {
-
-class Foo {
-public:
-  void Notify (TraceContext const &contex, uint64_t oldVal, uint64_t newVal) {}
-};
-
-class VariableTracerTest: public Test {
-public:
-  VariableTracerTest ();
-  void RunUnsignedTests (void);
-  void RunSignedUnsignedTests (void);
-  virtual bool RunTests (void);
-};
-void
-VariableTracerTest::RunUnsignedTests (void)
-{
-  UVTraceSource<uint32_t> var, ovar, tmp;
-  uint32_t utmp;
-  Foo *foo = new Foo ();
-  
-  var.AddCallback (MakeCallback (&Foo::Notify, foo), TraceContext ());
-
-  var = 10;
-  ovar = var;
-
-  if (var == ovar) 
-    {
-    }
-  if (var != ovar) 
-    {
-    }
-  if (var > ovar) 
-    {
-    }
-  if (var >= ovar) 
-    {
-    }
-  if (var < ovar)
-    {
-    }
-  
-  if (var <= ovar)
-
-  if (var == 1)
-    {
-    }
-  if (var != 1)
-    {
-    }
-  if (var > 1)
-    {
-    }
-  if (var >= 1)
-    {
-    }
-  if (var < 1)
-    {
-    }
-  if (var <= 1)
-    {
-    }
-
-  if (1 == ovar)
-    {
-    }
-  if (1 != ovar)
-    {
-    }
-  if (1 > ovar)
-    {
-    }
-  if (1 >= ovar)
-    {
-    }
-  if (1 < ovar)
-    {
-    }
-  if (1 <= ovar)
-    {
-    }
-
-  var++;
-  ++var;
-  var--;
-  --var;
-
-  tmp = var + ovar;
-  tmp = var - ovar;
-  tmp = var / ovar;
-  tmp = var * ovar;
-  tmp = var << ovar;
-  tmp = var >> ovar;
-  tmp = var & ovar;
-  tmp = var | ovar;
-  tmp = var ^ ovar;
-
-  tmp = var + 1;
-  tmp = var - 1;
-  tmp = var / 1;
-  tmp = var * 1;
-  tmp = var << 1;
-  tmp = var >> 1;
-  tmp = var & 1;
-  tmp = var | 1;
-  tmp = var ^ 1;
-
-  tmp = 1 + ovar;
-  tmp = 1 - ovar;
-  tmp = 1 / ovar;
-  tmp = 1 * ovar;
-  tmp = 1 << ovar;
-  tmp = 1 >> ovar;
-  tmp = 1 & ovar;
-  tmp = 1 | ovar;
-  tmp = 1 ^ ovar;
-
-  tmp += var;
-  tmp -= var;
-  tmp /= var;
-  tmp *= var;
-  tmp <<= var;
-  tmp >>= var;
-  tmp &= var;
-  tmp |= var;
-  tmp ^= var;
-
-  tmp += 1;
-  tmp -= 1;
-  tmp /= 1;
-  tmp *= 1;
-  tmp <<= 1;
-  tmp >>= 1;
-  tmp &= 1;
-  tmp |= 1;
-  tmp ^= 1;
-
-
-  utmp = var + ovar;
-  utmp = var - ovar;
-  utmp = var / ovar;
-  utmp = var * ovar;
-  utmp = var << ovar;
-  utmp = var >> ovar;
-  utmp = var & ovar;
-  utmp = var | ovar;
-  utmp = var ^ ovar;
-
-  utmp = var + 1;
-  utmp = var - 1;
-  utmp = var / 1;
-  utmp = var * 1;
-  utmp = var << 1;
-  utmp = var >> 1;
-  utmp = var & 1;
-  utmp = var | 1;
-  utmp = var ^ 1;
-
-  utmp = 1 + ovar;
-  utmp = 1 - ovar;
-  utmp = 1 / ovar;
-  utmp = 1 * ovar;
-  utmp = 1 << ovar;
-  utmp = 1 >> ovar;
-  utmp = 1 & ovar;
-  utmp = 1 | ovar;
-  utmp = 1 ^ ovar;
-
-  utmp += var;
-  utmp -= var;
-  utmp /= var;
-  utmp *= var;
-  utmp <<= var;
-  utmp >>= var;
-  utmp &= var;
-  utmp |= var;
-  utmp ^= var;
-
-  utmp += 1;
-  utmp -= 1;
-  utmp /= 1;
-  utmp *= 1;
-  utmp <<= 1;
-  utmp >>= 1;
-  utmp &= 1;
-  utmp |= 1;
-  utmp ^= 1;
-
-  delete foo;
-}
-
-void
-VariableTracerTest::RunSignedUnsignedTests (void)
-{
-  unsigned short utmp = 10;
-  unsigned int uitmp = 7;
-  short stmp = 5;
-  utmp = stmp;
-  utmp += stmp;
-  uitmp = utmp;
-  utmp = uitmp;
-
-  UVTraceSource<unsigned short> uvar = 10;
-  UVTraceSource<unsigned int> uivar = 5;
-  SVTraceSource<short> svar = 5;
-  SVTraceSource<int> sivar = 5;
-  uvar = svar;
-  svar = uvar;
-  uvar += svar;
-  svar += uvar;
-
-  uvar = sivar;
-  sivar = uvar;
-  uvar += sivar;
-  sivar += uvar;
-
-  uivar = uvar;
-  uvar = uivar;
-  uivar += uvar;
-  uvar += uivar;
-
-  sivar = svar;
-  svar = sivar;
-  sivar += svar;
-  svar += sivar;
-}
-
-bool 
-VariableTracerTest::RunTests (void)
-{
-  RunUnsignedTests ();
-  RunSignedUnsignedTests ();
-
-  return true;
-}
-
-VariableTracerTest::VariableTracerTest ()
-  : Test ("VariableTracer") {}
-
-static VariableTracerTest gVariableTracerTest;
-
-}; // namespace ns3
-
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/waf	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,1 @@
+exec "`dirname "$0"`"/../../waf "$@"
\ No newline at end of file
--- a/src/common/wscript	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/common/wscript	Fri Sep 28 11:59:46 2007 +0100
@@ -1,49 +1,32 @@
 ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
 
-def configure(conf):
-    conf.env.append_value('NS3_MODULES', 'ns3-common')
-
 def build(bld):
-    common = bld.create_obj('cpp', 'shlib')
-    common.name = 'ns3-common'
-    common.target = common.name
-    common.uselib_local = ['ns3-core', 'ns3-simulator']
+    common = bld.create_ns3_module('common', ['core', 'simulator'])
     common.source = [
         'buffer.cc',
-        'header.cc',
-        'chunk.cc',
-        'trailer.cc',
+        'chunk-registry.cc',
+        'packet-printer.cc',
+        'packet-metadata.cc',
+        'packet-metadata-test.cc',
         'packet.cc',
         'tags.cc',
+        'tag-registry.cc',
         'pcap-writer.cc',
-        'variable-tracer-test.cc',
-        'trace-context.cc',
-        'trace-resolver.cc',
-        'callback-trace-source.cc',
-        'empty-trace-resolver.cc',
-        'composite-trace-resolver.cc',
-        'trace-root.cc',
         'data-rate.cc',
         ]
+
     headers = bld.create_obj('ns3header')
     headers.source = [
         'buffer.h',
+        'chunk-registry.h',
         'header.h',
-        'chunk.h',
         'trailer.h',
         'tags.h',
+        'tag-registry.h',
+        'tag.h',
         'packet.h',
-        'uv-trace-source.h',
-        'sv-trace-source.h',
-        'fv-trace-source.h',
+        'packet-printer.h',
+        'packet-metadata.h',
         'pcap-writer.h',
-        'callback-trace-source.h',
-        'trace-context.h',
-        'trace-resolver.h',
-        'empty-trace-resolver.h',
-        'composite-trace-resolver.h',
-        'array-trace-resolver.h',
-        'trace-root.h',
-        'terminal-trace-resolver.h',
         'data-rate.h',
         ]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/array-trace-resolver.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,205 @@
+/* -*- 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
+ * 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 ARRAY_TRACE_RESOLVER_H
+#define ARRAY_TRACE_RESOLVER_H
+
+#include <stdint.h>
+#include <string>
+#include "callback.h"
+#include "trace-resolver.h"
+#include "object.h"
+
+namespace ns3 {
+
+/**
+ * \brief a helper class to offer trace resolution for an array of objects.
+ * \ingroup tracing
+ *
+ * \class ArrayTraceResolver
+ *
+ * An ArrayTraceResolver is a resolver which can match any input integer
+ * against an element in an array. The array is accessed using a 
+ * pair iterators. Each element of the array is expected
+ * to be a subclass of the Object base class.
+ * 
+ * When the Connect method is called, this trace resolver will 
+ * automatically store in the TraceContext of each resolved object
+ * its index through an object of type INDEX specified during the
+ * instanciation of the ArrayTraceResolver template.
+ */
+template <typename INDEX>
+class ArrayTraceResolver : public TraceResolver
+{
+public:
+  ArrayTraceResolver ();
+  ~ArrayTraceResolver ();
+
+  /**
+   * \param begin an iterator which points to the start of the array.
+   * \param end an iterator which points to the end of the array.
+   */
+  template <typename T>
+  void SetIterators (T begin, T end);
+
+  // inherited from TraceResolver
+  virtual void Connect (std::string path, CallbackBase const &cb, const TraceContext &context);
+  virtual void Disconnect (std::string path, CallbackBase const &cb);
+  virtual void CollectSources (std::string path, const TraceContext &context, 
+                               SourceCollection *collection);
+  virtual void TraceAll (std::ostream &os, const TraceContext &context);
+
+private:
+  class IteratorBase
+  {
+  public:
+    virtual ~IteratorBase () {}
+    virtual void Next (void) = 0;
+    virtual bool HasNext (void) = 0;
+    virtual Ptr<Object> Get (void) = 0;
+    virtual void Rewind (void) = 0;
+  };
+  IteratorBase *m_iter;
+};
+}//namespace ns3
+
+
+// implementation
+namespace ns3 {
+
+template <typename INDEX>
+ArrayTraceResolver<INDEX>::ArrayTraceResolver ()
+  : m_iter (0)
+{}
+
+template <typename INDEX>
+ArrayTraceResolver<INDEX>::~ArrayTraceResolver ()
+{
+  delete m_iter;
+}
+
+template <typename INDEX>
+template <typename T>
+void
+ArrayTraceResolver<INDEX>::SetIterators (T begin, T end)
+{
+  class Iterator : public IteratorBase 
+  {
+  public:
+    Iterator (T begin, T end)
+      : m_begin (begin), m_end (end), m_cur (begin)
+    {}
+    virtual void Next (void)
+    {m_cur++;}
+    virtual bool HasNext (void)
+    {return m_cur != m_end;}
+    virtual Ptr<Object> Get (void)
+    {return *m_cur;}
+    virtual void Rewind (void)
+    {m_cur = m_begin;}
+  private:
+    T m_begin;
+    T m_end;
+    T m_cur;
+  };
+  delete m_iter;
+  m_iter = new Iterator (begin, end);
+}
+
+template <typename INDEX>
+void 
+ArrayTraceResolver<INDEX>::Connect (std::string path, CallbackBase const &cb, const TraceContext &context)
+{
+  if (path == "")
+    {
+      return;
+    }
+  std::string id = GetElement (path);
+  std::string subpath = GetSubpath (path);
+  if (id == "*")
+  {
+    uint32_t j = 0;
+    for (m_iter->Rewind (); m_iter->HasNext (); m_iter->Next ())
+      {
+        TraceContext tmp = context;
+        INDEX index = j;
+        tmp.AddElement (index);
+        Ptr<Object> obj = m_iter->Get ();
+        obj->GetTraceResolver ()->Connect (subpath, cb, tmp);
+        j++;
+      }
+  }
+}
+template <typename INDEX>
+void 
+ArrayTraceResolver<INDEX>::Disconnect (std::string path, CallbackBase const &cb)
+{
+  if (path == "")
+    {
+      return;
+    }
+  std::string id = GetElement (path);
+  std::string subpath = GetSubpath (path);
+  if (id == "*")
+  {
+    for (m_iter->Rewind (); m_iter->HasNext (); m_iter->Next ())
+      {
+        Ptr<Object> obj = m_iter->Get ();
+        obj->TraceDisconnect (subpath, cb);
+      }
+  }
+}
+template <typename INDEX>
+void 
+ArrayTraceResolver<INDEX>::CollectSources (std::string path, const TraceContext &context, 
+                                           SourceCollection *collection)
+{
+  path.append ("/[0-n]");
+  uint32_t j = 0;
+  for (m_iter->Rewind (); m_iter->HasNext (); m_iter->Next ())
+    {
+        TraceContext tmp = context;
+        INDEX index = j;
+        tmp.AddElement (index);
+        Ptr<Object> obj = m_iter->Get ();
+        obj->GetTraceResolver ()->CollectSources (path, tmp, collection);
+        j++;
+    }
+}
+
+template <typename INDEX>
+void 
+ArrayTraceResolver<INDEX>::TraceAll (std::ostream &os, const TraceContext &context)
+{
+  uint32_t j = 0;
+  for (m_iter->Rewind (); m_iter->HasNext (); m_iter->Next ())
+    {
+        TraceContext tmp = context;
+        INDEX index = j;
+        tmp.AddElement (index);
+        Ptr<Object> obj = m_iter->Get ();
+        obj->GetTraceResolver ()->TraceAll (os, tmp);
+        j++;
+    }
+}
+
+}//namespace ns3
+
+#endif /* ARRAY_TRACE_RESOLVER_H */
--- a/src/core/assert.cc	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2006 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
- * 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 "assert.h"
-
-namespace ns3 {
-
-void
-AssertBreakpoint (void)
-{
-  int *a = 0;
-  /**
-   * we test here to allow a debugger to change the value of
-   * the variable 'a' to allow the debugger to avoid the 
-   * subsequent segfault.
-   */
-  if (a == 0)
-    {
-      *a = 0;
-    }
-}
-
-}//namespace ns3
--- a/src/core/assert.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/assert.h	Fri Sep 28 11:59:46 2007 +0100
@@ -21,6 +21,12 @@
 #ifndef ASSERT_H
 #define ASSERT_H
 
+#ifdef NS3_ASSERT_ENABLE
+
+#include <iostream>
+
+#include "breakpoint.h"
+
 /**
  * \defgroup assert Assert
  * \brief assert functions and macros
@@ -32,25 +38,6 @@
  * removed in optimized builds.
  */
 
-namespace ns3 {
-
-/**
- * \ingroup debugging
- *
- * When an NS_ASSERT cannot verify its condition, 
- * this function is called. This is where you should
- * be able to put a breakpoint with a debugger if
- * you want to catch assertions before the program 
- * halts.
- */
-void AssertBreakpoint (void);
-
-}//namespace ns3
-
-#ifdef NS3_ASSERT_ENABLE
-
-#include <iostream>
-
 /**
  * \ingroup assert
  * \param condition condition to verifiy.
@@ -65,10 +52,10 @@
     {                                                           \
       if (!(condition))                                         \
         {                                                       \
-          std::cout << "assert failed. file=" << __FILE__ <<    \
+          std::cerr << "assert failed. file=" << __FILE__ <<    \
             ", line=" << __LINE__ << ", cond=\""#condition <<   \
             "\"" << std::endl;                                  \
-          ns3::AssertBreakpoint ();                             \
+          NS_BREAKPOINT ();                                     \
         }                                                       \
     }                                                           \
   while (false)
@@ -88,8 +75,8 @@
     {                                           \
       if (!(condition))                         \
         {                                       \
-          std::cout << message << std::endl;    \
-          ns3::AssertBreakpoint ();             \
+          std::cerr << message << std::endl;    \
+          NS_BREAKPOINT ();                     \
         }                                       \
     }                                           \
   while (false)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/breakpoint.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,58 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006,2007 INRIA, INESC Porto
+ * 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
+ * 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>
+ * Author: Gustavo Carneiro <gjc@inescporto.pt>
+ */
+
+#include "breakpoint.h"
+#include "ns3/core-config.h"
+#ifdef HAVE_SIGNAL_H
+# include <signal.h>
+#endif
+
+namespace ns3 {
+
+#if defined (HAVE_SIGNAL_H) && defined (SIGTRAP)
+
+void
+BreakpointFallback (void)
+{
+  raise (SIGTRAP);
+}
+
+#else
+
+void
+BreakpointFallback (void)
+{
+  int *a = 0;
+  /**
+   * we test here to allow a debugger to change the value of
+   * the variable 'a' to allow the debugger to avoid the 
+   * subsequent segfault.
+   */
+  if (a == 0)
+    {
+      *a = 0;
+    }
+}
+
+#endif // HAVE_SIGNAL_H
+
+}//namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/breakpoint.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,76 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006,2007 INESC Porto, 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
+ * 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: Gustavo Carneiro <gjc@inescporto.pt>
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef BREAKPOINT_H
+#define BREAKPOINT_H
+
+namespace ns3 {
+
+/* Hacker macro to place breakpoints for selected machines.
+ * Actual use is strongly discouraged of course ;)
+ * Copied from GLib 2.12.9.
+ * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GLib Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+/**
+ * \ingroup debugging
+ *
+ * Inserts a breakpoint instruction (or equivalent system call) into
+ * the code for selected machines.  When an NS_ASSERT cannot verify its condition, 
+ * this macro is used. Falls back to calling
+ * AssertBreakpoint() for architectures where breakpoint assembly
+ * instructions are not supported.
+ */
+#if (defined (__i386__) || defined (__amd64__) || defined (__x86_64__)) && defined (__GNUC__) && __GNUC__ >= 2
+#  define NS_BREAKPOINT() \
+   do{ __asm__ __volatile__ ("int $03"); }while(false)
+#elif defined (_MSC_VER) && defined (_M_IX86)
+#  define NS_BREAKPOINT() \
+   do{ __asm int 3h }while(false)
+#elif defined (__alpha__) && !defined(__osf__) && defined (__GNUC__) && __GNUC__ >= 2
+#  define NS_BREAKPOINT() \
+   do{ __asm__ __volatile__ ("bpt"); }while(false)
+#else	/* !__i386__ && !__alpha__ */
+#  define NS_BREAKPOINT()    ns3::BreakpointFallback ()
+#endif
+
+/**
+ * \brief fallback breakpoint function
+ *
+ * This function is used by the NS_BREAKPOINT() macro as a fallback
+ * for when breakpoint assembly instructions are not available.  It
+ * attempts to halt program execution either by a raising SIGTRAP, on
+ * unix systems, or by dereferencing a null pointer.
+ * 
+ * Normally you should not call this function directly.
+ */
+void BreakpointFallback (void);
+
+
+}//namespace ns3
+
+
+#endif /* BREAKPOINT_H */
--- a/src/core/callback-test.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/callback-test.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -57,6 +57,21 @@
   return a;
 }
 
+void TestFZero (void) {}
+void TestFOne (int) {}
+void TestFTwo (int, int) {}
+void TestFThree (int, int, int) {}
+void TestFFour (int, int, int, int) {}
+void TestFFive (int, int, int, int, int) {}
+void TestFSix (int, int, int, int, int, int) {}
+
+void TestFROne (int &) {}
+void TestFRTwo (int &, int &) {}
+void TestFRThree (int &, int &, int &) {}
+void TestFRFour (int &, int &, int &, int &) {}
+void TestFRFive (int &, int &, int &, int &, int &) {}
+void TestFRSix (int &, int &, int &, int &, int &, int &) {}
+
 class CallbackTest : public ns3::Test {
 private:
   bool m_test1;
@@ -73,6 +88,22 @@
   void Test3 (double a);
   int Test4 (double a, int b);
   void Test8 (Callback<void, int> callback);
+
+  void TestZero (void) {}
+  void TestOne (int) {}
+  void TestTwo (int, int) {}
+  void TestThree (int, int, int) {}
+  void TestFour (int, int, int, int) {}
+  void TestFive (int, int, int, int, int) {}
+  void TestSix (int, int, int, int, int, int) {}
+
+  void TestCZero (void) const {}
+  void TestCOne (int) const {}
+  void TestCTwo (int, int) const {}
+  void TestCThree (int, int, int) const {}
+  void TestCFour (int, int, int, int) const {}
+  void TestCFive (int, int, int, int, int) const {}
+  void TestCSix (int, int, int, int, int, int) const {}
 };
 
 CallbackTest::CallbackTest ()
@@ -110,6 +141,7 @@
 {
   callback (3);
 }
+
 bool
 CallbackTest::IsWrong (void)
 {
@@ -216,6 +248,53 @@
   MakeBoundCallback (&Test9, &v);
   MakeBoundCallback (&Test10, &v);
 
+
+  MakeCallback (&CallbackTest::TestZero, this);
+  MakeCallback (&CallbackTest::TestOne, this);
+  MakeCallback (&CallbackTest::TestTwo, this);
+  MakeCallback (&CallbackTest::TestThree, this);
+  MakeCallback (&CallbackTest::TestFour, this);
+  MakeCallback (&CallbackTest::TestFive, this);
+  MakeCallback (&CallbackTest::TestSix, this);
+
+  MakeCallback (&CallbackTest::TestCZero, this);
+  MakeCallback (&CallbackTest::TestCOne, this);
+  MakeCallback (&CallbackTest::TestCTwo, this);
+  MakeCallback (&CallbackTest::TestCThree, this);
+  MakeCallback (&CallbackTest::TestCFour, this);
+  MakeCallback (&CallbackTest::TestCFive, this);
+  MakeCallback (&CallbackTest::TestCSix, this);
+
+  MakeCallback (&TestFZero);
+  MakeCallback (&TestFOne);
+  MakeCallback (&TestFTwo);
+  MakeCallback (&TestFThree);
+  MakeCallback (&TestFFour);
+  MakeCallback (&TestFFive);
+  MakeCallback (&TestFSix);
+
+  MakeCallback (&TestFROne);
+  MakeCallback (&TestFRTwo);
+  MakeCallback (&TestFRThree);
+  MakeCallback (&TestFRFour);
+  MakeCallback (&TestFRFive);
+  MakeCallback (&TestFRSix);
+
+
+  MakeBoundCallback (&TestFOne, 1);
+  MakeBoundCallback (&TestFTwo, 1);
+  MakeBoundCallback (&TestFThree, 1);
+  MakeBoundCallback (&TestFFour, 1);
+  MakeBoundCallback (&TestFFive, 1);
+
+  MakeBoundCallback (&TestFROne, 1);
+  MakeBoundCallback (&TestFRTwo, 1);
+  MakeBoundCallback (&TestFRThree, 1);
+  MakeBoundCallback (&TestFRFour, 1);
+  MakeBoundCallback (&TestFRFive, 1);
+
+
+
   return ok;
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/callback-trace-source.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,101 @@
+/* -*- 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
+ * 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 "callback-trace-source.h"
+
+#ifdef RUN_SELF_TESTS
+
+#include "test.h"
+
+namespace ns3 {
+
+class CallbackTraceSourceTest : public Test 
+{
+public:
+  CallbackTraceSourceTest ();
+  virtual ~CallbackTraceSourceTest ();
+  virtual bool RunTests (void);
+private:
+  void CbOne (TraceContext const &context, uint8_t a, double b);
+  void CbTwo (TraceContext const &context, uint8_t a, double b);
+
+  bool m_one;
+  bool m_two;
+};
+
+CallbackTraceSourceTest::CallbackTraceSourceTest ()
+  : Test ("CallbackTraceSource")
+{}
+CallbackTraceSourceTest::~CallbackTraceSourceTest ()
+{}
+void
+CallbackTraceSourceTest::CbOne (TraceContext const &context, uint8_t a, double b)
+{
+  m_one = true;
+}
+void
+CallbackTraceSourceTest::CbTwo (TraceContext const &context, uint8_t a, double b)
+{
+  m_two = true;
+}
+bool 
+CallbackTraceSourceTest::RunTests (void)
+{
+  bool result = true;
+  TraceContext ctx;
+
+  CallbackTraceSource<uint8_t,double> trace;
+  trace.AddCallback (MakeCallback (&CallbackTraceSourceTest::CbOne, this), ctx);
+  trace.AddCallback (MakeCallback (&CallbackTraceSourceTest::CbTwo, this), ctx);
+  m_one = false;
+  m_two = false;
+  trace (1, 2);
+  NS_TEST_ASSERT (m_one);
+  NS_TEST_ASSERT (m_two);
+
+  trace.RemoveCallback (MakeCallback (&CallbackTraceSourceTest::CbOne, this));
+  m_one = false;
+  m_two = false;
+  trace (1, 2);
+  NS_TEST_ASSERT (!m_one);
+  NS_TEST_ASSERT (m_two);
+  trace.RemoveCallback (MakeCallback (&CallbackTraceSourceTest::CbTwo, this));
+  m_one = false;
+  m_two = false;
+  trace (1, 2);
+  NS_TEST_ASSERT (!m_one);
+  NS_TEST_ASSERT (!m_two);
+
+  trace.AddCallback (MakeCallback (&CallbackTraceSourceTest::CbOne, this), ctx);
+  trace.AddCallback (MakeCallback (&CallbackTraceSourceTest::CbTwo, this), ctx);
+  m_one = false;
+  m_two = false;
+  trace (1, 2);
+  NS_TEST_ASSERT (m_one);
+  NS_TEST_ASSERT (m_two);
+
+  return result;
+}
+
+CallbackTraceSourceTest g_callbackTraceTest;
+
+}//namespace ns3
+
+#endif /* RUN_SELF_TESTS */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/callback-trace-source.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,251 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2005,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
+ * 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 CALLBACK_TRACE_H
+#define CALLBACK_TRACE_H
+
+#include <list>
+#include "callback.h"
+#include "fatal-error.h"
+#include "trace-context.h"
+#include "trace-source.h"
+
+namespace ns3 {
+
+/**
+ * \brief log arbitrary number of parameters to a matching ns3::Callback
+ * \ingroup tracing
+ *
+ * Whenever operator () is invoked on this class, the call and its arguments
+ * are forwarded to the internal matching ns3::Callback.
+ */
+template<typename T1 = empty, typename T2 = empty, 
+         typename T3 = empty, typename T4 = empty>
+class CallbackTraceSource : public TraceSource {
+public:
+  CallbackTraceSource ();
+  virtual void AddCallback (CallbackBase const & callback, TraceContext const & context);
+  virtual void RemoveCallback (CallbackBase const & callback);
+  virtual void ConnectPrinter (std::ostream &os, const TraceContext &context);
+  void operator() (void) const;
+  void operator() (T1 a1) const;
+  void operator() (T1 a1, T2 a2) const;
+  void operator() (T1 a1, T2 a2, T3 a3) const;
+  void operator() (T1 a1, T2 a2, T3 a3, T4 a4) const;
+
+private:
+  typedef std::list<Callback<void,TraceContext const &,T1,T2,T3,T4> > CallbackList;
+  TraceContext m_context;
+  CallbackList m_callbackList;
+};
+
+}; // namespace ns3
+
+// implementation below.
+
+namespace ns3 {
+
+namespace internal {
+
+template<typename T1, typename T2, 
+         typename T3, typename T4>
+class TraceSinkPrint;
+
+template<typename T1, typename T2, 
+         typename T3, typename T4>
+class TraceSinkPrint
+{
+public:
+  static Callback<void,const TraceContext &,T1,T2,T3,T4> Make (std::ostream &os)
+  {
+    return ns3::MakeBoundCallback (&DoPrint, &os);
+  }
+private:
+  static void DoPrint (std::ostream *os, const TraceContext &context, T1 a1, T2 a2, T3 a3, T4 a4)
+  {
+    *os << "context=\"" << context << "\" arg1=\"" << a1 << "\" arg2=\"" << a2 << "\" arg3=\"" << a3 << "\" arg4=\"" << a4 << "\"" << std::endl;
+  }
+};
+
+template<typename T1, typename T2, 
+         typename T3>
+class TraceSinkPrint<T1,T2,T3,empty>
+{
+public:
+  static Callback<void,const TraceContext &,T1,T2,T3> Make (std::ostream &os)
+  {
+    return ns3::MakeBoundCallback (&DoPrint, &os);
+  }
+private:
+  static void DoPrint (std::ostream *os, const TraceContext &context, T1 a1, T2 a2, T3 a3)
+  {
+    *os << "context=\"" << context << "\" arg1=\"" << a1 << "\" arg2=\"" << a2 << "\" arg3=\"" << a3 << "\"" << std::endl;
+  }
+};
+
+template<typename T1, typename T2>
+class TraceSinkPrint<T1,T2,empty,empty>
+{
+public:
+  static Callback<void,const TraceContext &,T1,T2> Make (std::ostream &os)
+  {
+    return ns3::MakeBoundCallback (&DoPrint, &os);
+  }
+private:
+  static void DoPrint (std::ostream *os, const TraceContext &context, T1 a1, T2 a2)
+  {
+    *os << "context=\"" << context << "\" arg1=\"" << a1 << "\" arg2=\"" << a2 << "\"" << std::endl;
+  }
+};
+
+template<typename T1>
+class TraceSinkPrint<T1,empty,empty,empty>
+{
+public:
+  static Callback<void,const TraceContext &,T1> Make (std::ostream &os)
+  {
+    return ns3::MakeBoundCallback (&DoPrint, &os);
+  }
+private:
+  static void DoPrint (std::ostream *os, const TraceContext &context, T1 a1)
+  {
+    *os << "context=\"" << context << "\" arg1=\"" << a1 << "\"" << std::endl;
+  }
+};
+
+template <>
+class TraceSinkPrint<empty,empty,empty,empty>
+{
+public:
+  static Callback<void,const TraceContext &> Make (std::ostream &os)
+  {
+    return ns3::MakeBoundCallback (&DoPrint, &os);
+  }
+private:
+  static void DoPrint (std::ostream *os, const TraceContext &context)
+  {
+    *os << "context=\"" << context << std::endl;
+  }
+};
+
+} // namespace internal
+
+
+template<typename T1, typename T2, 
+         typename T3, typename T4>
+CallbackTraceSource<T1,T2,T3,T4>::CallbackTraceSource ()
+  : m_callbackList () 
+{}
+template<typename T1, typename T2, 
+         typename T3, typename T4>
+void 
+CallbackTraceSource<T1,T2,T3,T4>::AddCallback (CallbackBase const & callback,
+                                               TraceContext const &context)
+{
+  Callback<void,TraceContext const &,T1,T2,T3,T4> cb;
+  cb.Assign (callback);
+  m_context.Union (context);
+  m_callbackList.push_back (cb);
+}
+template<typename T1, typename T2, 
+         typename T3, typename T4>
+void 
+CallbackTraceSource<T1,T2,T3,T4>::RemoveCallback (CallbackBase const & callback)
+{
+  for (typename CallbackList::iterator i = m_callbackList.begin ();
+       i != m_callbackList.end (); /* empty */)
+    {
+      if ((*i).IsEqual (callback))
+	{
+	  i = m_callbackList.erase (i);
+	}
+      else
+	{
+	  i++;
+	}
+    }
+}
+template<typename T1, typename T2, 
+         typename T3, typename T4>
+void 
+CallbackTraceSource<T1,T2,T3,T4>::ConnectPrinter (std::ostream &os, const TraceContext &context)
+{
+  AddCallback (ns3::internal::TraceSinkPrint<T1,T2,T3,T4>::Make (os), context);
+}
+template<typename T1, typename T2, 
+         typename T3, typename T4>
+void 
+CallbackTraceSource<T1,T2,T3,T4>::operator() (void) const
+{
+  for (typename CallbackList::const_iterator i = m_callbackList.begin ();
+       i != m_callbackList.end (); i++)
+    {
+      (*i) (m_context);
+    }
+}
+template<typename T1, typename T2, 
+         typename T3, typename T4>
+void 
+CallbackTraceSource<T1,T2,T3,T4>::operator() (T1 a1) const
+{
+  for (typename CallbackList::const_iterator i = m_callbackList.begin ();
+       i != m_callbackList.end (); i++)
+    {
+      (*i) (m_context, a1);
+    }
+}
+template<typename T1, typename T2, 
+         typename T3, typename T4>
+void 
+CallbackTraceSource<T1,T2,T3,T4>::operator() (T1 a1, T2 a2) const
+{
+  for (typename CallbackList::const_iterator i = m_callbackList.begin ();
+       i != m_callbackList.end (); i++)
+    {
+      (*i) (m_context, a1, a2);
+    }
+}
+template<typename T1, typename T2, 
+         typename T3, typename T4>
+void 
+CallbackTraceSource<T1,T2,T3,T4>::operator() (T1 a1, T2 a2, T3 a3) const
+{
+  for (typename CallbackList::const_iterator i = m_callbackList.begin ();
+       i != m_callbackList.end (); i++)
+    {
+      (*i) (m_context, a1, a2, a3);
+    }
+}
+template<typename T1, typename T2, 
+         typename T3, typename T4>
+void 
+CallbackTraceSource<T1,T2,T3,T4>::operator() (T1 a1, T2 a2, T3 a3, T4 a4) const
+{
+  for (typename CallbackList::const_iterator i = m_callbackList.begin ();
+       i != m_callbackList.end (); i++)
+    {
+      (*i) (m_context, a1, a2, a3, a4);
+    }
+}
+
+}//namespace ns3
+
+#endif /* CALLBACK_TRACE_H */
--- a/src/core/callback.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/callback.h	Fri Sep 28 11:59:46 2007 +0100
@@ -25,6 +25,7 @@
 #include "ptr.h"
 #include "fatal-error.h"
 #include "empty.h"
+#include "type-traits.h"
 
 namespace ns3 {
 
@@ -89,55 +90,62 @@
 };
 
 // declare the CallbackImpl class
-template <typename R, typename T1, typename T2, typename T3, typename T4, typename T5>
+template <typename R, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
 class CallbackImpl;
 // define CallbackImpl for 0 params
 template <typename R>
-class CallbackImpl<R,empty,empty,empty,empty,empty> : public CallbackImplBase {
+class CallbackImpl<R,empty,empty,empty,empty,empty,empty> : public CallbackImplBase {
 public:
   virtual ~CallbackImpl () {}
   virtual R operator() (void) = 0;
 };
 // define CallbackImpl for 1 params
 template <typename R, typename T1>
-class CallbackImpl<R,T1,empty,empty,empty,empty> : public CallbackImplBase {
+class CallbackImpl<R,T1,empty,empty,empty,empty,empty> : public CallbackImplBase {
 public:
   virtual ~CallbackImpl () {}
   virtual R operator() (T1) = 0;
 };
 // define CallbackImpl for 2 params
 template <typename R, typename T1, typename T2>
-class CallbackImpl<R,T1,T2,empty,empty,empty> : public CallbackImplBase {
+class CallbackImpl<R,T1,T2,empty,empty,empty,empty> : public CallbackImplBase {
 public:
   virtual ~CallbackImpl () {}
   virtual R operator() (T1, T2) = 0;
 };
 // define CallbackImpl for 3 params
 template <typename R, typename T1, typename T2, typename T3>
-class CallbackImpl<R,T1,T2,T3,empty,empty> : public CallbackImplBase {
+class CallbackImpl<R,T1,T2,T3,empty,empty,empty> : public CallbackImplBase {
 public:
   virtual ~CallbackImpl () {}
   virtual R operator() (T1, T2, T3) = 0;
 };
 // define CallbackImpl for 4 params
 template <typename R, typename T1, typename T2, typename T3, typename T4>
-class CallbackImpl<R,T1,T2,T3,T4,empty> : public CallbackImplBase {
+class CallbackImpl<R,T1,T2,T3,T4,empty,empty> : public CallbackImplBase {
 public:
   virtual ~CallbackImpl () {}
   virtual R operator() (T1, T2, T3, T4) = 0;
 };
 // define CallbackImpl for 5 params
 template <typename R, typename T1, typename T2, typename T3, typename T4, typename T5>
-class CallbackImpl : public CallbackImplBase {
+class CallbackImpl<R,T1,T2,T3,T4,T5,empty> : public CallbackImplBase {
 public:
   virtual ~CallbackImpl () {}
   virtual R operator() (T1, T2, T3, T4, T5) = 0;
 };
+// define CallbackImpl for 6 params
+  template <typename R, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
+class CallbackImpl : public CallbackImplBase {
+public:
+  virtual ~CallbackImpl () {}
+  virtual R operator() (T1, T2, T3, T4, T5, T6) = 0;
+};
 
 
 // an impl for Functors:
-template <typename T, typename R, typename T1, typename T2, typename T3, typename T4,typename T5>
-class FunctorCallbackImpl : public CallbackImpl<R,T1,T2,T3,T4,T5> {
+template <typename T, typename R, typename T1, typename T2, typename T3, typename T4,typename T5, typename T6>
+class FunctorCallbackImpl : public CallbackImpl<R,T1,T2,T3,T4,T5,T6> {
 public:
   FunctorCallbackImpl (T const &functor)
     : m_functor (functor) {}
@@ -160,9 +168,12 @@
   R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5) {
       return m_functor (a1,a2,a3,a4,a5);
   }
+  R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6) {
+    return m_functor (a1,a2,a3,a4,a5,a6);
+  }
   virtual bool IsEqual (CallbackImplBase const *other) const {
-    FunctorCallbackImpl<T,R,T1,T2,T3,T4,T5> const *otherDerived = 
-      dynamic_cast<FunctorCallbackImpl<T,R,T1,T2,T3,T4,T5> const *> (other);
+    FunctorCallbackImpl<T,R,T1,T2,T3,T4,T5,T6> const *otherDerived = 
+      dynamic_cast<FunctorCallbackImpl<T,R,T1,T2,T3,T4,T5,T6> const *> (other);
     if (otherDerived == 0)
       {
         return false;
@@ -178,8 +189,8 @@
 };
 
 // an impl for pointer to member functions
-template <typename OBJ_PTR, typename MEM_PTR, typename R, typename T1, typename T2, typename T3, typename T4, typename T5>
-class MemPtrCallbackImpl : public CallbackImpl<R,T1,T2,T3,T4,T5> {
+template <typename OBJ_PTR, typename MEM_PTR, typename R, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
+class MemPtrCallbackImpl : public CallbackImpl<R,T1,T2,T3,T4,T5,T6> {
 public:
   MemPtrCallbackImpl (OBJ_PTR const&objPtr, MEM_PTR mem_ptr)
     : m_objPtr (objPtr), m_memPtr (mem_ptr) {}
@@ -202,9 +213,12 @@
   R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5) {
     return ((CallbackTraits<OBJ_PTR>::GetReference (m_objPtr)).*m_memPtr) (a1, a2, a3, a4, a5);
   }
+  R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6) {
+    return ((CallbackTraits<OBJ_PTR>::GetReference (m_objPtr)).*m_memPtr) (a1, a2, a3, a4, a5, a6);
+  }
   virtual bool IsEqual (CallbackImplBase const *other) const {
-    MemPtrCallbackImpl<OBJ_PTR,MEM_PTR,R,T1,T2,T3,T4,T5> const *otherDerived = 
-      dynamic_cast<MemPtrCallbackImpl<OBJ_PTR,MEM_PTR,R,T1,T2,T3,T4,T5> const *> (other);
+    MemPtrCallbackImpl<OBJ_PTR,MEM_PTR,R,T1,T2,T3,T4,T5,T6> const *otherDerived = 
+      dynamic_cast<MemPtrCallbackImpl<OBJ_PTR,MEM_PTR,R,T1,T2,T3,T4,T5,T6> const *> (other);
     if (otherDerived == 0)
       {
         return false;
@@ -225,6 +239,7 @@
 public:
   virtual ~CallbackBase () {}
   virtual CallbackImplBase *PeekImpl (void) const = 0;
+  virtual Ptr<CallbackImplBase> GetImpl (void) const = 0;
 };
 
 /**
@@ -259,26 +274,26 @@
 template<typename R, 
    typename T1 = empty, typename T2 = empty, 
    typename T3 = empty, typename T4 = empty,
-   typename T5 = empty>
+   typename T5 = empty, typename T6 = empty>
 class Callback : public CallbackBase {
 public:
   // There are two dummy args below to ensure that this constructor is
   // always properly disambiguited by the c++ compiler
   template <typename FUNCTOR>
   Callback (FUNCTOR const &functor, bool, bool) 
-      : m_impl (Create<FunctorCallbackImpl<FUNCTOR,R,T1,T2,T3,T4,T5> > (functor))
+    : m_impl (Create<FunctorCallbackImpl<FUNCTOR,R,T1,T2,T3,T4,T5,T6> > (functor))
   {}
 
   template <typename OBJ_PTR, typename MEM_PTR>
   Callback (OBJ_PTR const &objPtr, MEM_PTR mem_ptr)
-      : m_impl (Create<MemPtrCallbackImpl<OBJ_PTR,MEM_PTR,R,T1,T2,T3,T4,T5> > (objPtr, mem_ptr))
+    : m_impl (Create<MemPtrCallbackImpl<OBJ_PTR,MEM_PTR,R,T1,T2,T3,T4,T5,T6> > (objPtr, mem_ptr))
   {}
 
-  Callback (Ptr<CallbackImpl<R,T1,T2,T3,T4,T5> > const &impl)
+  Callback (Ptr<CallbackImpl<R,T1,T2,T3,T4,T5,T6> > const &impl)
       : m_impl (impl)
   {}
 
-  bool IsNull (void) {
+  bool IsNull (void) const {
     return (PeekImpl () == 0)?true:false;
   }
   void Nullify (void) {
@@ -304,14 +319,17 @@
   R operator() (T1 a1, T2 a2, T3 a3, T4 a4,T5 a5) const {
     return (*(PeekImpl ())) (a1,a2,a3,a4,a5);
   }
+  R operator() (T1 a1, T2 a2, T3 a3, T4 a4,T5 a5,T6 a6) const {
+    return (*(PeekImpl ())) (a1,a2,a3,a4,a5,a6);
+  }
 
-  bool IsEqual (CallbackBase const &other) {
+  bool IsEqual (CallbackBase const &other) const {
     return PeekImpl ()->IsEqual (other.PeekImpl ());
   }
 
-  bool CheckType (CallbackBase const& other) {
+  bool CheckType (CallbackBase const& other) const {
     CallbackImplBase *otherBase = other.PeekImpl ();
-    if (dynamic_cast<CallbackImpl<R,T1,T2,T3,T4,T5> *> (otherBase) != 0)
+    if (dynamic_cast<CallbackImpl<R,T1,T2,T3,T4,T5,T6> *> (otherBase) != 0)
       {
         return true;
       }
@@ -327,14 +345,27 @@
                         " got=" << typeid (other).name () << 
                         ", expected=" << typeid (*this).name ());
       }
-    const Callback<R, T1,T2,T3,T4,T5> *goodType = static_cast<const Callback<R,T1,T2,T3,T4,T5> *> (&other);
+    const Callback<R, T1,T2,T3,T4,T5,T6> *goodType = static_cast<const Callback<R,T1,T2,T3,T4,T5,T6> *> (&other);
     *this = *goodType;
   }
+  void Assign (Ptr<CallbackImplBase> other) {
+    CallbackImpl<R,T1,T2,T3,T4,T5,T6> *impl = dynamic_cast<CallbackImpl<R,T1,T2,T3,T4,T5,T6> *> (PeekPointer (other));
+    if (other == 0)
+      {
+        NS_FATAL_ERROR ("Incompatible types. (feed to \"c++filt -t\")"
+                        " got=" << typeid (other).name () << 
+                        ", expected=" << typeid (*impl).name ());
+      }
+    *this = Callback<R,T1,T2,T3,T4,T5,T6> (impl);
+  }
+  virtual Ptr<CallbackImplBase>GetImpl (void) const {
+    return m_impl;
+  }
 private:
-  virtual CallbackImpl<R,T1,T2,T3,T4,T5> *PeekImpl (void) const {
+  virtual CallbackImpl<R,T1,T2,T3,T4,T5,T6> *PeekImpl (void) const {
     return PeekPointer (m_impl);
   }
-  Ptr<CallbackImpl<R,T1,T2,T3,T4,T5> > m_impl;
+  Ptr<CallbackImpl<R,T1,T2,T3,T4,T5,T6> > m_impl;
 };
 
 /**
@@ -344,7 +375,7 @@
 
 /**
  * \ingroup MakeCallback
- * \param mem_ptr class method member pointer
+ * \param memPtr class method member pointer
  * \param objPtr class instance
  * \return a wrapper Callback
  * Build Callbacks for class method members which takes no arguments
@@ -355,7 +386,7 @@
   return Callback<R> (objPtr, memPtr);
 }
 template <typename T, typename OBJ, typename R>
-Callback<R> MakeCallback (R (T::*mem_ptr) () const, OBJ const objPtr) {
+Callback<R> MakeCallback (R (T::*mem_ptr) () const, OBJ objPtr) {
   return Callback<R> (objPtr, mem_ptr);
 }
 /**
@@ -367,11 +398,11 @@
  * and potentially return a value.
  */
 template <typename T, typename OBJ, typename R, typename T1>
-Callback<R,T1> MakeCallback (R (T::*mem_ptr) (T1), OBJ *const objPtr) {
+Callback<R,T1> MakeCallback (R (T::*mem_ptr) (T1), OBJ objPtr) {
   return Callback<R,T1> (objPtr, mem_ptr);
 }
 template <typename T, typename OBJ, typename R, typename T1>
-Callback<R,T1> MakeCallback (R (T::*mem_ptr) (T1) const, OBJ const *const objPtr) {
+Callback<R,T1> MakeCallback (R (T::*mem_ptr) (T1) const, OBJ objPtr) {
   return Callback<R,T1> (objPtr, mem_ptr);
 }
 /**
@@ -383,11 +414,11 @@
  * and potentially return a value.
  */
 template <typename T, typename OBJ, typename R, typename T1, typename T2>
-Callback<R,T1,T2> MakeCallback (R (T::*mem_ptr) (T1,T2), OBJ *const objPtr) {
+Callback<R,T1,T2> MakeCallback (R (T::*mem_ptr) (T1,T2), OBJ objPtr) {
   return Callback<R,T1,T2> (objPtr, mem_ptr);
 }
 template <typename T, typename OBJ, typename R, typename T1, typename T2>
-Callback<R,T1,T2> MakeCallback (R (T::*mem_ptr) (T1,T2) const, OBJ const*const objPtr) {
+Callback<R,T1,T2> MakeCallback (R (T::*mem_ptr) (T1,T2) const, OBJ objPtr) {
   return Callback<R,T1,T2> (objPtr, mem_ptr);
 }
 /**
@@ -399,11 +430,11 @@
  * and potentially return a value.
  */
 template <typename T, typename OBJ, typename R, typename T1,typename T2, typename T3>
-Callback<R,T1,T2,T3> MakeCallback (R (T::*mem_ptr) (T1,T2,T3), OBJ *const objPtr) {
+Callback<R,T1,T2,T3> MakeCallback (R (T::*mem_ptr) (T1,T2,T3), OBJ objPtr) {
   return Callback<R,T1,T2,T3> (objPtr, mem_ptr);
 }
 template <typename T, typename OBJ, typename R, typename T1,typename T2, typename T3>
-Callback<R,T1,T2,T3> MakeCallback (R (T::*mem_ptr) (T1,T2,T3) const, OBJ const*const objPtr) {
+Callback<R,T1,T2,T3> MakeCallback (R (T::*mem_ptr) (T1,T2,T3) const, OBJ objPtr) {
   return Callback<R,T1,T2,T3> (objPtr, mem_ptr);
 }
 /**
@@ -415,11 +446,11 @@
  * and potentially return a value.
  */
 template <typename T, typename OBJ, typename R, typename T1, typename T2, typename T3, typename T4>
-Callback<R,T1,T2,T3,T4> MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4), OBJ *const objPtr) {
+Callback<R,T1,T2,T3,T4> MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4), OBJ objPtr) {
   return Callback<R,T1,T2,T3,T4> (objPtr, mem_ptr);
 }
 template <typename T, typename OBJ, typename R, typename T1, typename T2, typename T3, typename T4>
-Callback<R,T1,T2,T3,T4> MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4) const, OBJ const*const objPtr) {
+Callback<R,T1,T2,T3,T4> MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4) const, OBJ objPtr) {
   return Callback<R,T1,T2,T3,T4> (objPtr, mem_ptr);
 }
 /**
@@ -431,13 +462,29 @@
  * and potentially return a value.
  */
 template <typename T, typename OBJ, typename R, typename T1, typename T2, typename T3, typename T4,typename T5>
-Callback<R,T1,T2,T3,T4,T5> MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4,T5), OBJ *const objPtr) {
+Callback<R,T1,T2,T3,T4,T5> MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4,T5), OBJ objPtr) {
   return Callback<R,T1,T2,T3,T4,T5> (objPtr, mem_ptr);
 }
 template <typename T, typename OBJ, typename R, typename T1, typename T2, typename T3, typename T4,typename T5>
-Callback<R,T1,T2,T3,T4,T5> MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4,T5) const, OBJ const*const objPtr) {
+Callback<R,T1,T2,T3,T4,T5> MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4,T5) const, OBJ objPtr) {
   return Callback<R,T1,T2,T3,T4,T5> (objPtr, mem_ptr);
 }
+/**
+ * \ingroup MakeCallback
+ * \param mem_ptr class method member pointer
+ * \param objPtr class instance
+ * \return a wrapper Callback
+ * Build Callbacks for class method members which takes five arguments
+ * and potentially return a value.
+ */
+template <typename T, typename OBJ, typename R, typename T1, typename T2, typename T3, typename T4,typename T5,typename T6>
+Callback<R,T1,T2,T3,T4,T5,T6> MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4,T5,T6), OBJ objPtr) {
+  return Callback<R,T1,T2,T3,T4,T5,T6> (objPtr, mem_ptr);
+}
+template <typename T, typename OBJ, typename R, typename T1, typename T2, typename T3, typename T4,typename T5, typename T6>
+Callback<R,T1,T2,T3,T4,T5,T6> MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4,T5,T6) const, OBJ objPtr) {
+  return Callback<R,T1,T2,T3,T4,T5,T6> (objPtr, mem_ptr);
+}
 
 /**
  * \ingroup MakeCallback
@@ -505,6 +552,17 @@
 Callback<R,T1,T2,T3,T4,T5> MakeCallback (R (*fnPtr) (T1,T2,T3,T4,T5)) {
   return Callback<R,T1,T2,T3,T4,T5> (fnPtr, true, true);
 }
+/**
+ * \ingroup MakeCallback
+ * \param fnPtr function pointer
+ * \return a wrapper Callback
+ * Build Callbacks for functions which takes five arguments
+ * and potentially return a value.
+ */
+template <typename R, typename T1, typename T2,typename T3,typename T4,typename T5,typename T6>
+Callback<R,T1,T2,T3,T4,T5,T6> MakeCallback (R (*fnPtr) (T1,T2,T3,T4,T5,T6)) {
+  return Callback<R,T1,T2,T3,T4,T5,T6> (fnPtr, true, true);
+}
 
 
 
@@ -573,6 +631,17 @@
 Callback<R,T1,T2,T3,T4,T5> MakeNullCallback (void) {
   return Callback<R,T1,T2,T3,T4,T5> ();
 }
+/**
+ * \ingroup MakeCallback
+ * \overload Callback<R> MakeNullCallback (void)
+ * \return a wrapper Callback
+ * Build a null callback which takes five arguments
+ * and potentially return a value.
+ */
+template <typename R, typename T1, typename T2,typename T3,typename T4,typename T5,typename T6>
+Callback<R,T1,T2,T3,T4,T5,T6> MakeNullCallback (void) {
+  return Callback<R,T1,T2,T3,T4,T5,T6> ();
+}
 
 
 /*
@@ -582,9 +651,10 @@
  */
 // an impl for Bound Functors:
 template <typename T, typename R, typename TX, typename T1, typename T2, typename T3, typename T4,typename T5>
-class BoundFunctorCallbackImpl : public CallbackImpl<R,T1,T2,T3,T4,T5> {
+class BoundFunctorCallbackImpl : public CallbackImpl<R,T1,T2,T3,T4,T5,empty> {
 public:
-  BoundFunctorCallbackImpl (T const &functor, TX a)
+  template <typename FUNCTOR, typename ARG>
+  BoundFunctorCallbackImpl (FUNCTOR functor, ARG a)
       : m_functor (functor), m_a (a) {}
   virtual ~BoundFunctorCallbackImpl () {}
   R operator() (void) {
@@ -621,38 +691,48 @@
   }
 private:
   T m_functor;
-  TX m_a;
+  typename TypeTraits<TX>::ReferencedType m_a;
 };
 
-template <typename R, typename TX>
-Callback<R> MakeBoundCallback (R (*fnPtr) (TX), TX a) {
-  Ptr<CallbackImpl<R,empty,empty,empty,empty,empty> > impl =
+template <typename R, typename TX, typename ARG>
+Callback<R> MakeBoundCallback (R (*fnPtr) (TX), ARG a) {
+  Ptr<CallbackImpl<R,empty,empty,empty,empty,empty,empty> > impl =
     Create<BoundFunctorCallbackImpl<R (*) (TX),R,TX,empty,empty,empty,empty,empty> >(fnPtr, a);
   return Callback<R> (impl);
 }
 
-template <typename R, typename TX, typename T1>
-Callback<R,T1> MakeBoundCallback (R (*fnPtr) (TX,T1), TX a) {
-  Ptr<CallbackImpl<R,T1,empty,empty,empty,empty> > impl =
+template <typename R, typename TX, typename ARG, 
+          typename T1>
+Callback<R,T1> MakeBoundCallback (R (*fnPtr) (TX,T1), ARG a) {
+  Ptr<CallbackImpl<R,T1,empty,empty,empty,empty,empty> > impl =
     Create<BoundFunctorCallbackImpl<R (*) (TX,T1),R,TX,T1,empty,empty,empty,empty> > (fnPtr, a);
   return Callback<R,T1> (impl);
 }
-template <typename R, typename TX, typename T1, typename T2>
-Callback<R,T1,T2> MakeBoundCallback (R (*fnPtr) (TX,T1,T2), TX a) {
-  Ptr<CallbackImpl<R,T1,T2,empty,empty,empty> > impl =
+template <typename R, typename TX, typename ARG, 
+          typename T1, typename T2>
+Callback<R,T1,T2> MakeBoundCallback (R (*fnPtr) (TX,T1,T2), ARG a) {
+  Ptr<CallbackImpl<R,T1,T2,empty,empty,empty,empty> > impl =
     Create<BoundFunctorCallbackImpl<R (*) (TX,T1,T2),R,TX,T1,T2,empty,empty,empty> > (fnPtr, a);
   return Callback<R,T1,T2> (impl);
 }
-template <typename R, typename TX, typename T1, typename T2,typename T3,typename T4>
-Callback<R,T1,T2,T3,T4> MakeBoundCallback (R (*fnPtr) (TX,T1,T2,T3,T4), TX a) {
-  Ptr<CallbackImpl<R,T1,T2,T3,T4,empty> > impl =
+template <typename R, typename TX, typename ARG,
+          typename T1, typename T2,typename T3>
+Callback<R,T1,T2,T3> MakeBoundCallback (R (*fnPtr) (TX,T1,T2,T3), ARG a) {
+  Ptr<CallbackImpl<R,T1,T2,T3,empty,empty,empty> > impl =
+    Create<BoundFunctorCallbackImpl<R (*) (TX,T1,T2,T3),R,TX,T1,T2,T3,empty,empty> > (fnPtr, a);
+  return Callback<R,T1,T2,T3> (impl);
+}
+template <typename R, typename TX, typename ARG,
+          typename T1, typename T2,typename T3,typename T4>
+Callback<R,T1,T2,T3,T4> MakeBoundCallback (R (*fnPtr) (TX,T1,T2,T3,T4), ARG a) {
+  Ptr<CallbackImpl<R,T1,T2,T3,T4,empty,empty> > impl =
     Create<BoundFunctorCallbackImpl<R (*) (TX,T1,T2,T3,T4),R,TX,T1,T2,T3,T4,empty> > (fnPtr, a);
   return Callback<R,T1,T2,T3,T4> (impl);
 }
-
-template <typename R, typename TX, typename T1, typename T2,typename T3,typename T4,typename T5>
-Callback<R,T1,T2,T3,T4,T5> MakeBoundCallback (R (*fnPtr) (TX,T1,T2,T3,T4,T5), TX a) {
-  Ptr<CallbackImpl<R,T1,T2,T3,T4,T5> > impl =
+template <typename R, typename TX, typename ARG,
+          typename T1, typename T2,typename T3,typename T4,typename T5>
+Callback<R,T1,T2,T3,T4,T5> MakeBoundCallback (R (*fnPtr) (TX,T1,T2,T3,T4,T5), ARG a) {
+  Ptr<CallbackImpl<R,T1,T2,T3,T4,T5,empty> > impl =
     Create<BoundFunctorCallbackImpl<R (*) (TX,T1,T2,T3,T4,T5),R,TX,T1,T2,T3,T4,T5> > (fnPtr, a);
   return Callback<R,T1,T2,T3,T4,T5> (impl);
 }
--- a/src/core/component-manager.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/component-manager.h	Fri Sep 28 11:59:46 2007 +0100
@@ -348,7 +348,7 @@
    * result.
    */
   template <typename T, typename T1, typename T2, typename T3, typename T4, typename T5>
-  static Ptr<T> Create (ClassId classId, InterfaceId iid, T1 a1, T2 a2, T3 a3, T4 a4, T5);
+  static Ptr<T> Create (ClassId classId, InterfaceId iid, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
 
 private:
   friend void RegisterCallback (ClassId classId, CallbackBase *callback, 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/composite-trace-resolver.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,595 @@
+/* -*- 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
+ * 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 "composite-trace-resolver.h"
+#include "log.h"
+
+NS_LOG_COMPONENT_DEFINE ("CompositeTraceResolver");
+
+namespace ns3 {
+
+CompositeTraceResolver::CompositeTraceResolver ()
+{}
+
+CompositeTraceResolver::~CompositeTraceResolver ()
+{
+  for (TraceItems::iterator i = m_items.begin (); i != m_items.end (); i++)
+    {
+      delete *i;
+    }
+  m_items.clear ();
+}
+
+void 
+CompositeTraceResolver::AddItem (ResolveItem *item)
+{
+  m_items.push_back (item);
+}
+
+void 
+CompositeTraceResolver::Add (std::string name, 
+                             Callback<Ptr<TraceResolver> > createResolver)
+{
+  class MakerResolveItem : public ResolveItem
+  {
+  public:
+    virtual void Connect (std::string subpath, const CallbackBase &cb, const TraceContext &context)
+    {maker ()->Connect (subpath, cb, context);}
+    virtual void Disconnect (std::string subpath, const CallbackBase &cb)
+    {maker ()->Disconnect (subpath, cb);}
+    virtual void CollectSources (std::string path, const TraceContext &context, 
+                                 SourceCollection *collection)
+    {
+      path.append ("/");
+      path.append (this->name);
+      TraceContext ctx = context;
+      ctx.Union (this->context);
+      this->maker ()->CollectSources (path, ctx, collection);
+    }
+    virtual void TraceAll (std::ostream &os, const TraceContext &context)
+    {
+      TraceContext ctx = context;
+      ctx.Union (this->context);
+      this->maker ()->TraceAll (os, ctx);
+    }
+    Callback<Ptr<TraceResolver> > maker;
+  } *item = new MakerResolveItem ();
+  item->name = name;
+  item->context = TraceContext ();
+  item->maker = createResolver;
+  AddItem (item);
+}
+
+void 
+CompositeTraceResolver::AddSource (std::string name,
+                                   const TraceDoc &doc,
+                                   const TraceSource &trace)
+{
+  DoAddSource (name, doc, trace, TraceContext ());
+}
+
+void 
+CompositeTraceResolver::DoAddSource (std::string name,
+                                     const TraceDoc &doc,
+                                     const TraceSource &trace, 
+                                     const TraceContext &context)
+{
+  class SourceResolveItem : public ResolveItem
+  {
+  public:
+    virtual void Connect (std::string subpath, const CallbackBase &cb, const TraceContext &context)
+    {if (subpath == "") {trace->AddCallback (cb, context);}}
+    virtual void Disconnect (std::string subpath, const CallbackBase &cb)
+    {if (subpath == "") {trace->RemoveCallback (cb);}}
+    virtual void CollectSources (std::string path, const TraceContext &context, 
+                                 SourceCollection *collection)
+    {
+      path.append ("/");
+      path.append (this->name);
+      TraceContext ctx = context;
+      ctx.Union (this->context);
+      collection->AddUnique (path, ctx, this->doc);
+    }
+    virtual void TraceAll (std::ostream &os, const TraceContext &context)
+    {
+      TraceContext ctx = context;
+      ctx.Union (this->context);
+      this->trace->ConnectPrinter (os, ctx);
+    }
+    TraceSource *trace;
+    TraceDoc doc;
+  } *item = new SourceResolveItem ();
+  item->name = name;
+  item->context = context;
+  item->trace = const_cast<TraceSource *> (&trace);
+  item->doc = doc;
+  AddItem (item);
+}
+
+
+
+
+void 
+CompositeTraceResolver::AddComposite (std::string name, Ptr<Object> composite)
+{
+  DoAddComposite (name, composite, TraceContext ());
+}
+void 
+CompositeTraceResolver::DoAddComposite (std::string name, Ptr<Object> composite, const TraceContext &context)
+{
+  class CompositeResolveItem : public ResolveItem
+  {
+  public:
+    virtual void Connect (std::string subpath, const CallbackBase &cb, const TraceContext &context)
+    {composite->GetTraceResolver ()->Connect (subpath, cb, context);}
+    virtual void Disconnect (std::string subpath, const CallbackBase &cb)
+    {composite->TraceDisconnect (subpath, cb);}
+    virtual void CollectSources (std::string path, const TraceContext &context, 
+                                 SourceCollection *collection)
+    {
+      path.append ("/");
+      path.append (this->name);
+      TraceContext ctx = context;
+      ctx.Union (this->context);
+      this->composite->GetTraceResolver ()->CollectSources (path, ctx, collection);
+    }
+    virtual void TraceAll (std::ostream &os, const TraceContext &context)
+    {
+      TraceContext ctx = context;
+      ctx.Union (this->context);
+      this->composite->GetTraceResolver ()->TraceAll (os, ctx);
+    }
+
+    Ptr<Object> composite;
+  } *item = new CompositeResolveItem ();
+  item->name = name;
+  item->context = context;
+  item->composite = composite;
+  AddItem (item);
+}
+
+void
+CompositeTraceResolver::SetParentResolver (Ptr<TraceResolver> resolver)
+{
+  m_parent = resolver;
+}
+
+void 
+CompositeTraceResolver::Connect (std::string path, CallbackBase const &cb, const TraceContext &context)
+{
+  NS_LOG_LOGIC ("connect path="<<path);
+  class ConnectOperation : public Operation
+  {
+  public:
+    ConnectOperation (const CallbackBase &cb, const TraceContext &context)
+      : m_cb (cb), m_context (context)
+    {}
+    virtual void Do (std::string subpath, ResolveItem *item) const
+    {
+      NS_LOG_LOGIC ("connect to path="<<subpath<<" name="<<item->name);
+      TraceContext context = m_context;
+      context.Union (item->context);
+      item->Connect (subpath, m_cb, context);
+    }
+    virtual void DoParent (std::string path, Ptr<TraceResolver> parent) const
+    {
+      if (parent != 0)
+        {
+          parent->Connect (path, m_cb, m_context);
+        }
+    }
+  private:
+    const CallbackBase &m_cb;
+    const TraceContext &m_context;
+  } operation  = ConnectOperation (cb, context);
+  DoRecursiveOperation (path, operation);
+}
+void 
+CompositeTraceResolver::DoRecursiveOperation (std::string path, 
+                                              const Operation &operation)
+{
+  if (path == "")
+    {
+      return;
+    }
+  std::string id = GetElement (path);
+  std::string subpath = GetSubpath (path);
+
+  if (id == "*")
+    {
+      for (TraceItems::const_iterator i = m_items.begin (); i != m_items.end (); i++)
+	{
+          operation.Do (subpath, *i);
+        }
+      operation.DoParent (path, m_parent);
+      return;
+    }
+  std::string::size_type start, end;
+  start = id.find_first_of ("(", 0);
+  end = id.find_first_of (")", 0);
+  if (start != 0 || end != (id.size ()-1))
+    {
+      for (TraceItems::const_iterator i = m_items.begin (); i != m_items.end (); i++)
+	{
+	  if ((*i)->name == id)
+	    {
+              operation.Do (subpath, *i);
+              operation.DoParent (path, m_parent);
+              return;
+	    }
+	}
+    }
+  std::list<std::string> names;
+  std::string alternatives = std::string (id, start+1, end-1);
+  std::string::size_type next_pos, cur_pos;
+  next_pos = 0;
+  cur_pos = 0;
+  while (true)
+    {
+      std::string element;
+      next_pos = alternatives.find ("|", cur_pos);
+      if (next_pos == std::string::npos)
+	{
+	  element = std::string (alternatives, cur_pos, alternatives.size ());
+	  names.push_back (element);
+	  break;
+	}
+      element = std::string (alternatives, cur_pos, next_pos);
+      names.push_back (element);
+      cur_pos = next_pos + 1;
+    }
+  for (std::list<std::string>::const_iterator i = names.begin (); i != names.end (); i++)
+    {
+      for (TraceItems::const_iterator j = m_items.begin (); j != m_items.end (); j++)
+	{
+	  if ((*j)->name == *i)
+	    {
+              operation.Do (subpath, *j);
+	      break;
+	    }
+	}
+    }
+  operation.DoParent (path, m_parent);
+}
+
+void 
+CompositeTraceResolver::Disconnect (std::string path, CallbackBase const &cb)
+{
+  NS_LOG_LOGIC ("disconnect path="<<path);
+  class DisconnectOperation : public Operation
+  {
+  public:
+    DisconnectOperation (const CallbackBase &cb)
+      : m_cb (cb)
+    {}
+    virtual void Do (std::string subpath, ResolveItem *item) const
+    {
+      NS_LOG_LOGIC ("disconnect from path="<<subpath<<" name="<<item->name);
+      item->Disconnect (subpath, m_cb);
+    }
+    virtual void DoParent (std::string path, Ptr<TraceResolver> parent) const
+    {
+      if (parent != 0)
+        {
+          parent->Disconnect (path, m_cb);
+        }
+    }
+  private:
+    const CallbackBase &m_cb;
+  } operation  = DisconnectOperation (cb);
+  DoRecursiveOperation (path, operation);
+}
+
+void 
+CompositeTraceResolver::CollectSources (std::string path, const TraceContext &context, 
+                                        SourceCollection *collection)
+{
+  for (TraceItems::const_iterator i = m_items.begin (); i != m_items.end (); i++)
+    {
+      NS_LOG_LOGIC ("print " << (*i)->name);
+      (*i)->CollectSources (path, context, collection);
+    }
+  if (m_parent != 0)
+    {
+      m_parent->CollectSources (path, context, collection);
+    }
+}
+void 
+CompositeTraceResolver::TraceAll (std::ostream &os, const TraceContext &context)
+{
+  for (TraceItems::const_iterator i = m_items.begin (); i != m_items.end (); i++)
+    {
+      NS_LOG_LOGIC ("print " << (*i)->name);
+      (*i)->TraceAll (os, context);
+    }
+  if (m_parent != 0)
+    {
+      m_parent->TraceAll (os, context);
+    }  
+}
+
+
+}//namespace ns3
+
+#ifdef RUN_SELF_TESTS
+
+#include "test.h"
+#include "trace-context-element.h"
+
+namespace ns3 {
+
+class TraceSourceTest : public TraceContextElement
+{
+public:
+  enum Sources {
+    DOUBLEA,
+    DOUBLEB,
+    UINT16_T
+  };
+  static uint16_t GetUid (void) 
+  {static uint16_t uid = AllocateUid<TraceSourceTest> ("TraceSourceTest"); return uid;}
+  void Print (std::ostream &os)
+  {os << "tracesource=";
+    if (m_sources == DOUBLEA) {os << "doubleA";}
+    else if (m_sources == DOUBLEB) {os << "doubleB";}
+    else if (m_sources == UINT16_T) {os << "uint16_t";}
+  }
+  std::string GetTypeName (void) {return "ns3::TraceSourceTest";}
+  TraceSourceTest () : m_sources (TraceSourceTest::DOUBLEA) {}
+  TraceSourceTest (enum Sources sources) :m_sources (sources) {}
+  bool IsDoubleA (void) const {return m_sources == TraceSourceTest::DOUBLEA;}
+  bool IsDoubleB (void) const {return m_sources == TraceSourceTest::DOUBLEB;}
+  bool IsUint16 (void) const {return m_sources == TraceSourceTest::UINT16_T;}
+private:
+  enum TraceSourceTest::Sources m_sources;
+};
+
+class SubTraceSourceTest : public TraceContextElement
+{
+public:
+  enum Sources {
+    INT,
+  };
+  static uint16_t GetUid (void) 
+  {static uint16_t uid = AllocateUid<SubTraceSourceTest> ("SubTraceSourceTest"); return uid;}
+  void Print (std::ostream &os)
+  {os << "subtracesource=int";}
+  std::string GetTypeName (void) const {return "ns3::SubTraceSourceTest";}
+  SubTraceSourceTest () : m_sources (SubTraceSourceTest::INT) {}
+  SubTraceSourceTest (enum Sources sources) : m_sources (sources) {}
+private:
+  enum Sources m_sources;
+};
+
+class CompositeTraceResolverTest : public Test
+{
+public:
+  CompositeTraceResolverTest ();
+  virtual ~CompositeTraceResolverTest ();
+  virtual bool RunTests (void);
+private:
+  void TraceDouble (TraceContext const &context, double v);
+  void TraceInt (TraceContext const &context, int v);
+  Ptr<TraceResolver> CreateSubResolver ();
+
+
+  bool m_gotDoubleA;
+  bool m_gotDoubleB;
+  CallbackTraceSource<int> m_traceInt;
+  bool m_gotInt;
+};
+
+CompositeTraceResolverTest::CompositeTraceResolverTest ()
+  : Test ("CompositeTraceResolver")
+{}
+CompositeTraceResolverTest::~CompositeTraceResolverTest ()
+{}
+void 
+CompositeTraceResolverTest::TraceDouble (TraceContext const &context, double v)
+{
+  TraceSourceTest source;
+  context.GetElement (source);
+  if (source.IsDoubleA ())
+    {
+      m_gotDoubleA = true;
+    }
+  else if (source.IsDoubleB ())
+    {
+      m_gotDoubleB = true;
+    }
+  else
+    {
+      NS_FATAL_ERROR ("should not get any other trace source in this sink");
+    }
+  
+}
+
+void 
+CompositeTraceResolverTest::TraceInt (TraceContext const &context, int v)
+{
+  m_gotInt = true;
+}
+
+Ptr<TraceResolver>
+CompositeTraceResolverTest::CreateSubResolver (void)
+{
+  Ptr<CompositeTraceResolver> subresolver = Create<CompositeTraceResolver> ();
+  subresolver->AddSource ("trace-int", TraceDoc ("test source"), m_traceInt, 
+                          SubTraceSourceTest (SubTraceSourceTest::INT));
+  return subresolver;
+}
+bool 
+CompositeTraceResolverTest::RunTests (void)
+{
+  bool ok = true;
+
+  CallbackTraceSource<double> traceDoubleA;
+  CallbackTraceSource<double> traceDoubleB;
+  TraceContext context;
+
+  CompositeTraceResolver resolver;
+
+  resolver.AddSource ("trace-double-a", TraceDoc ("test source"), traceDoubleA, 
+                      TraceSourceTest (TraceSourceTest::DOUBLEA));
+  resolver.AddSource ("trace-double-b", TraceDoc ("test source"), traceDoubleB, 
+                      TraceSourceTest (TraceSourceTest::DOUBLEB));
+
+  resolver.Connect ("/*", MakeCallback (&CompositeTraceResolverTest::TraceDouble, this), TraceContext ());
+
+  m_gotDoubleA = false;
+  m_gotDoubleB = false;
+  traceDoubleA (0);
+  if (!m_gotDoubleA || m_gotDoubleB)
+    {
+      ok = false;
+    }
+  m_gotDoubleA = false;
+  traceDoubleA (0);
+  traceDoubleB (0);
+  if (!m_gotDoubleA || !m_gotDoubleB)
+    {
+      ok = false;
+    }
+  m_gotDoubleA = false;
+  m_gotDoubleB = false;
+
+  resolver.Disconnect ("/*", MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
+
+  m_gotDoubleA = false;
+  m_gotDoubleB = false;
+  traceDoubleA (0);
+  traceDoubleB (0);
+  if (m_gotDoubleA || m_gotDoubleB)
+    {
+      ok = false;
+    }
+
+  resolver.Connect ("/trace-double-a", 
+		    MakeCallback (&CompositeTraceResolverTest::TraceDouble, this), TraceContext ());
+  m_gotDoubleA = false;
+  m_gotDoubleB = false;
+  traceDoubleA (0);
+  traceDoubleB (0);
+  if (!m_gotDoubleA || m_gotDoubleB)
+    {
+      ok = false;
+    }
+  resolver.Disconnect ("/trace-double-a", 
+		       MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
+
+  resolver.Connect ("/(trace-double-a)", 
+		    MakeCallback (&CompositeTraceResolverTest::TraceDouble, this), TraceContext ());
+  m_gotDoubleA = false;
+  m_gotDoubleB = false;
+  traceDoubleA (0);
+  traceDoubleB (0);
+  if (!m_gotDoubleA || m_gotDoubleB)
+    {
+      ok = false;
+    }
+  resolver.Disconnect ("/trace-double-a", 
+		       MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
+
+  resolver.Connect ("/(trace-double-a|trace-double-b)", 
+		    MakeCallback (&CompositeTraceResolverTest::TraceDouble, this), TraceContext ());
+  m_gotDoubleA = false;
+  m_gotDoubleB = false;
+  traceDoubleA (0);
+  traceDoubleB (0);
+  if (!m_gotDoubleA || !m_gotDoubleB)
+    {
+      ok = false;
+    }
+  resolver.Disconnect ("/trace-double-a", 
+		       MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
+  m_gotDoubleA = false;
+  m_gotDoubleB = false;
+  traceDoubleA (0);
+  traceDoubleB (0);
+  if (m_gotDoubleA || !m_gotDoubleB)
+    {
+      ok = false;
+    }
+
+
+  resolver.Disconnect ("/(trace-double-a|trace-double-b)", 
+		       MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
+  m_gotDoubleA = false;
+  m_gotDoubleB = false;
+  traceDoubleA (0);
+  traceDoubleB (0);
+  if (m_gotDoubleA || m_gotDoubleB)
+    {
+      ok = false;
+    }
+
+  resolver.Add ("subresolver", 
+                MakeCallback (&CompositeTraceResolverTest::CreateSubResolver, this));
+
+  resolver.Connect ("/subresolver/trace-int", 
+		    MakeCallback (&CompositeTraceResolverTest::TraceInt, this), TraceContext ());
+  m_gotInt = false;
+  m_traceInt (1);
+  if (!m_gotInt)
+    {
+      ok = false;
+    }
+
+  resolver.Disconnect ("/subresolver/trace-int", 
+		       MakeCallback (&CompositeTraceResolverTest::TraceInt, this));
+  m_gotInt = false;
+  m_traceInt (1);
+  if (m_gotInt)
+    {
+      ok = false;
+    }
+
+  resolver.Connect ("/*/trace-int", 
+		    MakeCallback (&CompositeTraceResolverTest::TraceInt, this), TraceContext ());
+  m_gotInt = false;
+  m_traceInt (1);
+  if (!m_gotInt)
+    {
+      ok = false;
+    }
+
+  resolver.Disconnect ("/subresolver/trace-int", 
+		       MakeCallback (&CompositeTraceResolverTest::TraceInt, this));
+  m_gotInt = false;
+  m_traceInt (1);
+  if (m_gotInt)
+    {
+      ok = false;
+    }
+
+  SVTraceSource<uint16_t> source;
+
+  resolver.AddSource ("uint16_t", TraceDoc ("test source"), source, TraceSourceTest (TraceSourceTest::UINT16_T));
+  
+
+  return ok;
+}
+
+static CompositeTraceResolverTest g_compositeTraceResolverTest;
+
+}//namespace ns3
+
+
+#endif /* RUN_SELF_TESTS */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/composite-trace-resolver.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,233 @@
+/* -*- 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
+ * 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 COMPOSITE_TRACE_RESOLVER_H
+#define COMPOSITE_TRACE_RESOLVER_H
+
+#include <vector>
+#include "callback.h"
+#include "ptr.h"
+#include "trace-resolver.h"
+#include "callback-trace-source.h"
+#include "uv-trace-source.h"
+#include "sv-trace-source.h"
+#include "fv-trace-source.h"
+#include "array-trace-resolver.h"
+#include "trace-doc.h"
+
+namespace ns3 {
+
+/**
+ * \brief a helper class to aggregate contained TraceResolver and other trace sources.
+ * \ingroup tracing
+ */
+class CompositeTraceResolver : public TraceResolver
+{
+public:
+  CompositeTraceResolver ();
+  virtual ~CompositeTraceResolver ();
+  /**
+   * \param name name of trace source
+   * \param doc the documentation associated to this trace source
+   * \param trace a callback trace source
+   * \param context the context associated to this trace source
+   *
+   * Add a callback trace source in this resolver. This trace
+   * source will match the name specified during namespace 
+   * resolution. The TraceContext of this trace source will also
+   * be automatically extended to contain the input context.
+   */
+  template <typename T>
+  void AddSource (std::string name, const TraceDoc &doc,
+                  const TraceSource &trace, T const &context);
+  /**
+   * \param name name of trace source
+   * \param doc the documentation associated to this trace source
+   * \param trace a callback trace source
+   *
+   * Add a callback trace source in this resolver. This trace
+   * source will match the name specified during namespace 
+   * resolution.
+   */
+  void AddSource (std::string name,
+                  const TraceDoc &doc,
+                  const TraceSource &trace);
+
+  /**
+   * \param name the name of the composite element
+   * \param composite the composite object
+   *
+   * The input composite object will be used to resolve a connection
+   * of a disconnection attempt if its name matches the trace path.
+   * 
+   */
+  void AddComposite (std::string name, Ptr<Object> composite);
+
+  /**
+   * \param name the name of the composite element
+   * \param composite the composite object
+   * \param contextElement the context element associated to the composite
+   *
+   * The input composite object will be used to resolve a connection
+   * of a disconnection attempt if its name matches the trace path.
+   * The contextElement will be appended to the TraceContext during connection.
+   */
+  template <typename T>
+  void AddComposite (std::string name, Ptr<Object> composite, const T &contextElement);
+
+  /**
+   * \param name the name of the array
+   * \param begin an iterator which points to the first element of the array
+   * \param end an iterator which points to the last element of the array
+   * \param index an object which can store the index of an element in the
+   *        array. In practice, this object should support a constructor
+   *        whose single argument is an array index.
+   */
+  template <typename ITERATOR, typename INDEX>
+  void AddArray (std::string name, 
+                 ITERATOR begin, ITERATOR end, INDEX index);
+
+  /**
+   * \param parent the parent trace resolver
+   *
+   * The parent trace resolver is the trace resolver returned by the 
+   * GetTraceResolver method of the base class of the caller. It is 
+   * used during connection and disconnection to chain up the connect
+   * and disconnect calls to the parent.
+   */
+  void SetParentResolver (Ptr<TraceResolver> parent);
+
+
+private:
+  virtual void Connect (std::string path, CallbackBase const &cb, const TraceContext &context);
+  virtual void Disconnect (std::string path, CallbackBase const &cb);
+  virtual void CollectSources (std::string path, const TraceContext &context, 
+                               SourceCollection *collection);
+  virtual void TraceAll (std::ostream &os, const TraceContext &context);
+  friend class CompositeTraceResolverTest;
+  class ResolveItem 
+  {
+  public:
+    virtual ~ResolveItem () {}
+    virtual void Connect (std::string subpath, const CallbackBase &cb, const TraceContext &context) = 0;
+    virtual void Disconnect (std::string subpath, const CallbackBase &cb) = 0;
+    virtual void CollectSources (std::string path, const TraceContext &context, 
+                                 SourceCollection *collection) = 0;
+    virtual void TraceAll (std::ostream &os, const TraceContext &context) = 0;
+
+    std::string name;
+    TraceContext context;
+  };
+  typedef std::vector<ResolveItem *> TraceItems;
+  class Operation
+  {
+  public:
+    virtual ~Operation () {}
+    virtual void Do (std::string subpath, ResolveItem *item) const = 0;
+    virtual void DoParent (std::string path, Ptr<TraceResolver> parent) const = 0;
+  };
+
+  void AddItem (ResolveItem *item);
+  void DoRecursiveOperation (std::string path, 
+                             const Operation &operation);
+  void DoRecursiveOperationForParent (std::string path, 
+                                      const Operation &operation);
+  void DoAddComposite (std::string name, Ptr<Object> composite, const TraceContext &context);
+  void DoAddSource (std::string name,
+                    const TraceDoc &doc,
+                    const TraceSource &trace,
+                    const TraceContext &context);
+  void Add (std::string name, 
+            Callback<Ptr<TraceResolver> > createResolver);
+
+
+  CompositeTraceResolver::TraceItems m_items;
+  Ptr<TraceResolver> m_parent;
+};
+
+}//namespace ns3
+
+namespace ns3 {
+
+
+
+template <typename T>
+void 
+CompositeTraceResolver::AddSource (std::string name,
+                                   const TraceDoc &doc,
+                                   const TraceSource &trace, 
+                                   T const &context)
+{
+  TraceContext ctx;
+  ctx.AddElement (context);
+  DoAddSource (name, doc, trace, ctx);  
+}
+
+template <typename ITERATOR, typename INDEX>
+void 
+CompositeTraceResolver::AddArray (std::string name, 
+                                  ITERATOR begin, ITERATOR end, INDEX index)
+{
+  class ArrayResolveItem : public ResolveItem
+  {
+  public:
+    virtual void Connect (std::string subpath, const CallbackBase &cb, const TraceContext &context)
+    {array->Connect (subpath, cb, context);}
+    virtual void Disconnect (std::string subpath, const CallbackBase &cb)
+    {array->Disconnect (subpath, cb);}
+    virtual void CollectSources (std::string path, const TraceContext &context, 
+                                 SourceCollection *collection)
+    {
+      path.append ("/");
+      path.append (this->name);
+      TraceContext ctx = context;
+      ctx.Union (this->context);
+      array->CollectSources (path, ctx, collection);
+    }
+    virtual void TraceAll (std::ostream &os, const TraceContext &context)
+    {
+      TraceContext ctx = context;
+      ctx.Union (this->context);
+      array->TraceAll (os, ctx);
+    }
+
+    Ptr<ArrayTraceResolver<INDEX> > array;
+  } *item = new ArrayResolveItem ();
+  item->name = name;
+  item->context = TraceContext ();
+  item->array = Create<ArrayTraceResolver<INDEX> > ();
+  item->array->SetIterators (begin, end);
+  AddItem (item);
+}
+
+template <typename T>
+void 
+CompositeTraceResolver::AddComposite (std::string name, Ptr<Object> composite, const T &contextElement)
+{
+  TraceContext context;
+  context.AddElement (contextElement);
+  DoAddComposite (name, composite, context);
+}
+
+
+
+}//namespace ns3
+
+#endif /* COMPOSITE_TRACE_RESOLVER_H */
--- a/src/core/debug.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/debug.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -24,6 +24,7 @@
 #include "debug.h"
 #include "assert.h"
 #include "ns3/core-config.h"
+#include "fatal-error.h"
 
 #ifdef HAVE_STDLIB_H
 #include <stdlib.h>
@@ -53,6 +54,7 @@
     {
       return;
     }
+  bool allFound = true;
   std::string env = envVar;
   std::string::size_type cur = 0;
   std::string::size_type next = 0;
@@ -88,7 +90,7 @@
         }
       if (!found)
         {
-          std::cout << "No debug component named=\"" << tmp << "\"" << std::endl;
+          allFound = false;
         }
       if (next == std::string::npos)
         {
@@ -100,6 +102,11 @@
           break;
         }
     }
+  if (allFound)
+    {
+      g_firstDebug = true;
+    }
+  
 #endif
 }
 
@@ -122,7 +129,6 @@
   if (g_firstDebug) 
     {
       DebugComponentEnableEnvVar ();
-      g_firstDebug = false;
     }
   return m_isEnabled;
 }
--- a/src/core/debug.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/debug.h	Fri Sep 28 11:59:46 2007 +0100
@@ -110,7 +110,7 @@
     {                                           \
       if (g_debug.IsEnabled ())			\
         {                                       \
-          std::cout << msg << std::endl;        \
+          std::cerr << msg << std::endl;        \
         }                                       \
     }                                           \
   while (false)
@@ -125,7 +125,7 @@
 #define NS_DEBUG_UNCOND(msg)         \
   do                                 \
     {                                \
-      std::cout << msg << std::endl; \
+      std::cerr << msg << std::endl; \
     }                                \
   while (false)
 
--- a/src/core/default-value.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/default-value.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -23,6 +23,52 @@
 
 namespace ns3 {
 
+namespace DefaultValue {
+
+enum BindStatus {
+  OK,
+  INVALID_VALUE,
+  NOT_FOUND
+};
+
+
+static 
+enum BindStatus
+BindSafe (std::string name, std::string value)
+{
+  for (DefaultValueList::Iterator i = DefaultValueList::Begin ();
+       i != DefaultValueList::End (); i++)
+    {
+      DefaultValueBase *cur = *i;
+      if (cur->GetName () == name)
+	{
+	  if (!cur->ParseValue (value))
+	    {
+	      return INVALID_VALUE;
+	    }
+	  return OK;
+	}
+    }
+  return NOT_FOUND;
+}
+
+void
+Bind (std::string name, std::string value)
+{
+  switch (BindSafe (name, value)) {
+  case INVALID_VALUE:
+    NS_FATAL_ERROR ("Invalid value: "<<name<<"="<<value);
+    break;
+  case NOT_FOUND:
+    NS_FATAL_ERROR ("No registered DefaultValue=\"" << name << "\"");
+    break;
+  case OK:
+    break;
+  }
+}
+
+}
+
 DefaultValueBase::DefaultValueBase (const std::string &name,
 				    const std::string &help)
   : m_name (name),
@@ -112,48 +158,6 @@
   return &list;
 }
 
-enum BindStatus {
-  OK,
-  INVALID_VALUE,
-  NOT_FOUND
-};
-
-
-static 
-enum BindStatus
-BindSafe (std::string name, std::string value)
-{
-  for (DefaultValueList::Iterator i = DefaultValueList::Begin ();
-       i != DefaultValueList::End (); i++)
-    {
-      DefaultValueBase *cur = *i;
-      if (cur->GetName () == name)
-	{
-	  if (!cur->ParseValue (value))
-	    {
-	      return INVALID_VALUE;
-	    }
-	  return OK;
-	}
-    }
-  return NOT_FOUND;
-}
-
-void
-Bind (std::string name, std::string value)
-{
-  switch (BindSafe (name, value)) {
-  case INVALID_VALUE:
-    NS_FATAL_ERROR ("Invalid value: "<<name<<"="<<value);
-    break;
-  case NOT_FOUND:
-    NS_FATAL_ERROR ("No registered DefaultValue=\"" << name << "\"");
-    break;
-  case OK:
-    break;
-  }
-}
-
 BooleanDefaultValue::BooleanDefaultValue (std::string name,
 					  std::string help,
 					  bool defaultValue)
@@ -341,104 +345,53 @@
 bool 
 DefaultValueTest::RunTests (void)
 {
-  bool ok = true;
+  bool result = true;
 
   BooleanDefaultValue a ("bool-a", "help a", true);
-  if (!a.GetValue ())
-    {
-      ok = false;
-    }
-  Bind ("bool-a", "false");
-  if (a.GetValue ())
-    {
-      ok = false;
-    }
+  NS_TEST_ASSERT (a.GetValue ());
+  DefaultValue::Bind ("bool-a", "false");
+  NS_TEST_ASSERT (!a.GetValue ());
   BooleanDefaultValue b ("bool-b", "help b", false);
-  Bind ("bool-b", "true");
-  if (!b.GetValue ())
-    {
-      ok = false;
-    }
-  Bind ("bool-b", "0");
-  if (b.GetValue ())
-    {
-      ok = false;
-    }
-  Bind ("bool-b", "1");
-  if (!b.GetValue ())
-    {
-      ok = false;
-    }
-  Bind ("bool-b", "f");
-  if (b.GetValue ())
-    {
-      ok = false;
-    }
-  Bind ("bool-b", "t");
-  if (!b.GetValue ())
-    {
-      ok = false;
-    }
+  DefaultValue::Bind ("bool-b", "true");
+  NS_TEST_ASSERT (b.GetValue ());
+  DefaultValue::Bind ("bool-b", "0");
+  NS_TEST_ASSERT (!b.GetValue ());
+  DefaultValue::Bind ("bool-b", "1");
+  NS_TEST_ASSERT (b.GetValue ());
+  DefaultValue::Bind ("bool-b", "f");
+  NS_TEST_ASSERT (!b.GetValue ());
+  DefaultValue::Bind ("bool-b", "t");
+  NS_TEST_ASSERT (b.GetValue ());
 
-  Bind ("bool-b", "false");
-  if (b.GetValue ())
-    {
-      ok = false;
-    }
-  if (BindSafe ("bool-b", "tr") != INVALID_VALUE)
-    {
-      ok = false;
-    }
+  DefaultValue::Bind ("bool-b", "false");
+  NS_TEST_ASSERT (!b.GetValue ());
+  NS_TEST_ASSERT_EQUAL (DefaultValue::BindSafe ("bool-b", "tr"), DefaultValue::INVALID_VALUE)
 
-  IntegerDefaultValue<int> i ("test-i", "help-i", -1);
-  if (i.GetValue () != -1)
-    {
-      ok = false;
-    }  
-  Bind ("test-i", "-2");
-  if (i.GetValue () != -2)
-    {
-      ok = false;
-    }
-  Bind ("test-i", "+2");
-  if (i.GetValue () != 2)
-    {
-      ok = false;
-    }
-  if (i.GetType () != "int32_t(-2147483648:2147483647)")
-    {
-      ok = false;
-    }
-  IntegerDefaultValue<uint32_t> ui32 ("test-ui32", "help-ui32", 10);
-  if (ui32.GetType () != "uint32_t(0:4294967295)")
-    {
-      ok = false;
-    }
-  IntegerDefaultValue<char> c ("test-c", "help-c", 10);
-  if (c.GetValue () != 10)
-    {
-      ok = false;
-    }
-  Bind ("test-c", "257");  
+  NumericDefaultValue<int32_t> i ("test-i", "help-i", -1);
+  NS_TEST_ASSERT_EQUAL (i.GetValue (), -1);
+  DefaultValue::Bind ("test-i", "-2");
+  NS_TEST_ASSERT_EQUAL (i.GetValue (), -2);
+  DefaultValue::Bind ("test-i", "+2");
+  NS_TEST_ASSERT_EQUAL (i.GetValue (), 2);
+  NS_TEST_ASSERT_EQUAL (i.GetType (), "int32_t(-2147483648:2147483647)");
+  NumericDefaultValue<uint32_t> ui32 ("test-ui32", "help-ui32", 10);
+  NS_TEST_ASSERT_EQUAL (ui32.GetType (), "uint32_t(0:4294967295)");
+  NumericDefaultValue<int8_t> c ("test-c", "help-c", 10);
+  NS_TEST_ASSERT_EQUAL (c.GetValue (), 10);
+  DefaultValue::Bind ("test-c", "257");  
+  NumericDefaultValue<float> x ("test-x", "help-x", 10.0);
+  NumericDefaultValue<double> y ("test-y", "help-y", 10.0);
+
 
   EnumDefaultValue<enum MyEnum> e ("test-e", "help-e",
 				   MY_ENUM_C, "C",
 				   MY_ENUM_A, "A",
 				   MY_ENUM_B, "B",
 				   0, (void*)0);
-  if (e.GetValue () != MY_ENUM_C)
-    {
-      ok = false;
-    }
-  Bind ("test-e", "B");
-  if (e.GetValue () != MY_ENUM_B)
-    {
-      ok = false;
-    }
-  if (BindSafe ("test-e", "D") != INVALID_VALUE)
-    {
-      ok = false;
-    }
+  NS_TEST_ASSERT_EQUAL (e.GetValue (), MY_ENUM_C);
+  DefaultValue::Bind ("test-e", "B");
+  NS_TEST_ASSERT_EQUAL (e.GetValue (), MY_ENUM_B);
+  NS_TEST_ASSERT_EQUAL (DefaultValue::BindSafe ("test-e", "D"), DefaultValue::INVALID_VALUE);
 
   class MyEnumSubclass : public EnumDefaultValue<enum MyEnum>
   {
@@ -453,15 +406,9 @@
       AddPossibleValue (MY_ENUM_D, "D");
     }
   } e1 ;
-  if (e1.GetValue () != MY_ENUM_B)
-    {
-      ok = false;
-    }
-  Bind ("test-e1", "D");
-  if (e1.GetValue () != MY_ENUM_D)
-    {
-      ok = false;
-    }
+  NS_TEST_ASSERT_EQUAL (e1.GetValue (), MY_ENUM_B);
+  DefaultValue::Bind ("test-e1", "D");
+  NS_TEST_ASSERT_EQUAL (e1.GetValue (), MY_ENUM_D);
 
   DefaultValueList::Remove ("test-e1");
   DefaultValueList::Remove ("test-e");
@@ -471,7 +418,7 @@
   DefaultValueList::Remove ("test-c");
   DefaultValueList::Remove ("test-ui32");
   
-  return ok;
+  return result;
 }
 
 static DefaultValueTest g_default_value_tests;
--- a/src/core/default-value.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/default-value.h	Fri Sep 28 11:59:46 2007 +0100
@@ -31,6 +31,25 @@
 
 namespace ns3 {
 
+namespace DefaultValue
+{
+
+/**
+ * \ingroup config
+ * \param name name of variable to bind
+ * \param value value to bind to the specified variable
+ *
+ * If the variable name does not match any existing
+ * variable or if the value is not compatible with
+ * the variable type, this function will abort
+ * at runtime and print an error message detailing
+ * which variable or value triggered the problem.
+ */
+void Bind (std::string name, std::string value);
+
+}
+
+
 class DefaultValueBase
 {
 public:
@@ -84,19 +103,6 @@
 };
 
 /**
- * \ingroup config
- * \param name name of variable to bind
- * \param value value to bind to the specified variable
- *
- * If the variable name does not match any existing
- * variable or if the value is not compatible with
- * the variable type, this function will abort
- * at runtime and print an error message detailing
- * which variable or value triggered the problem.
- */
-void Bind (std::string name, std::string value);
-
-/**
  * \brief A Boolean variable for ns3::Bind
  * \ingroup config
  *
@@ -135,7 +141,7 @@
 };
 
 /**
- * \brief An Integer variable for ns3::Bind
+ * \brief A Numeric variable for ns3::Bind
  * \ingroup config
  *
  * Every instance of this type is automatically 
@@ -143,7 +149,7 @@
  * by ns3::Bind. 
  */
 template <typename T>
-class IntegerDefaultValue : public DefaultValueBase
+class NumericDefaultValue : public DefaultValueBase
 {
 public:
   /**
@@ -157,7 +163,7 @@
    * of values which can be stored and retrieved from the underlying
    * type.
    */
-  IntegerDefaultValue (std::string name,
+  NumericDefaultValue (std::string name,
 		       std::string help,
 		       T defaultValue);
   /**
@@ -169,7 +175,7 @@
    * \param minValue the minimum value which can be set
    *        in this variable
    */
-  IntegerDefaultValue (std::string name,
+  NumericDefaultValue (std::string name,
 		       std::string help,
 		       T defaultValue,
 		       T minValue);
@@ -185,7 +191,7 @@
    * \param maxValue the maximum value which can be set in this
    *        variable.
    */
-  IntegerDefaultValue (std::string name,
+  NumericDefaultValue (std::string name,
 		       std::string help,
 		       T defaultValue,
 		       T minValue,
@@ -351,7 +357,7 @@
 
 
 template <typename T>
-IntegerDefaultValue<T>::IntegerDefaultValue (std::string name,
+NumericDefaultValue<T>::NumericDefaultValue (std::string name,
 					     std::string help,
 					     T defaultValue)
   : DefaultValueBase (name, help),
@@ -364,7 +370,7 @@
   NS_ASSERT (m_minValue < m_maxValue);
 }
 template <typename T>
-IntegerDefaultValue<T>::IntegerDefaultValue (std::string name,
+NumericDefaultValue<T>::NumericDefaultValue (std::string name,
 					     std::string help,
 					     T defaultValue,
 					     T minValue)
@@ -380,7 +386,7 @@
 	     m_defaultValue >= m_minValue);
 }
 template <typename T>
-IntegerDefaultValue<T>::IntegerDefaultValue (std::string name,
+NumericDefaultValue<T>::NumericDefaultValue (std::string name,
 					     std::string help,
 					     T defaultValue,
 					     T minValue,
@@ -399,7 +405,7 @@
 
 template <typename T>
 void 
-IntegerDefaultValue<T>::SetValue (T v)
+NumericDefaultValue<T>::SetValue (T v)
 {
   NS_ASSERT (v <= m_maxValue &&
 	     v >= m_minValue);
@@ -408,14 +414,14 @@
 
 template <typename T>
 T
-IntegerDefaultValue<T>::GetValue (void) const
+NumericDefaultValue<T>::GetValue (void) const
 {
   return m_value;
 }
 
 template <typename T>
 bool
-IntegerDefaultValue<T>::DoParseValue (const std::string &value)
+NumericDefaultValue<T>::DoParseValue (const std::string &value)
 {
   std::istringstream iss;
   iss.str (value);
@@ -430,7 +436,7 @@
 
 template <typename T>
 std::string
-IntegerDefaultValue<T>::DoGetType (void) const
+NumericDefaultValue<T>::DoGetType (void) const
 {
   std::ostringstream oss;
   oss << TypeNameGet<T> () << "("
@@ -441,7 +447,7 @@
 
 template <typename T>
 std::string
-IntegerDefaultValue<T>::DoGetDefaultValue (void) const
+NumericDefaultValue<T>::DoGetDefaultValue (void) const
 {
   std::ostringstream oss;
   oss << m_defaultValue;
--- a/src/core/fatal-error.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/fatal-error.h	Fri Sep 28 11:59:46 2007 +0100
@@ -21,7 +21,7 @@
 #ifndef FATAL_ERROR_H
 #define FATAL_ERROR_H
 
-#include "assert.h"
+#include "breakpoint.h"
 #include <iostream>
 
 /**
@@ -32,15 +32,14 @@
  *
  * When this macro is hit at runtime, the user-specified 
  * error message is output and the program is halted by calling
- * the ns3::AssertBreakpoint function. This macro is enabled
- * unconditionally in all builds, including debug and optimized 
- * builds.
+ * the NS_BREAKPOINT macro. This macro is enabled unconditionally
+ * in all builds, including debug and optimized builds.
  */
 #define NS_FATAL_ERROR(msg)				\
   do                                                    \
     {                                                   \
-      std::cout << msg << std::endl;			\
-      ns3::AssertBreakpoint ();                         \
+      std::cerr << msg << std::endl;			\
+      NS_BREAKPOINT ();                                 \
     }                                                   \
   while (false)
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/fv-trace-source.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,71 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 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
+ * 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 F_VARIABLE_TRACER_H
+#define F_VARIABLE_TRACER_H
+
+#include "callback-trace-source.h"
+#include "trace-source.h"
+#include <stdint.h>
+
+namespace ns3 {
+
+class FVTraceSourceBase : public TraceSource {
+public:
+  typedef CallbackTraceSource<double, double> ChangeNotifyCallback;
+
+  FVTraceSourceBase () {}
+  FVTraceSourceBase (FVTraceSourceBase const &o) {}
+  FVTraceSourceBase &operator = (FVTraceSourceBase const &o) {
+      return *this;
+  }
+
+  ~FVTraceSourceBase () {}
+
+  virtual void AddCallback (CallbackBase const & callback, TraceContext const & context) {
+    m_callback.AddCallback (callback, context);
+  }
+  virtual void RemoveCallback (CallbackBase const & callback) {
+    m_callback.RemoveCallback (callback);
+  }
+  virtual void ConnectPrinter (std::ostream &os, const TraceContext &context) {
+    m_callback.ConnectPrinter (os, context);
+  }
+protected:
+  void notify (double oldVal, double newVal) {
+      if (oldVal != newVal) 
+        {
+          m_callback (oldVal, newVal);
+        }
+  }
+private:
+  ChangeNotifyCallback m_callback;
+};
+
+template <typename T>
+class FVTraceSource : public FVTraceSourceBase 
+{
+public:
+};
+
+}; // namespace ns3
+
+#endif /* F_VARIABLE_TRACER_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/log.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,331 @@
+/* -*- 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>
+ */
+
+#ifdef NS3_LOG_ENABLE
+
+#include <list>
+#include <utility>
+#include <iostream>
+#include "log.h"
+#include "assert.h"
+#include "ns3/core-config.h"
+#include "fatal-error.h"
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+namespace ns3 {
+
+typedef std::list<std::pair <std::string, LogComponent *> > ComponentList;
+typedef std::list<std::pair <std::string, LogComponent *> >::iterator ComponentListI;
+
+static 
+ComponentList *GetComponentList (void)
+{
+  static ComponentList components;
+  return &components;
+}
+
+void
+LogComponentEnableEnvVar (void)
+{
+  static bool isFirstLog = true;
+  if (!isFirstLog)
+    {
+      return;
+    }
+#ifdef HAVE_GETENV
+  char *envVar = getenv("NS_LOG");
+  if (envVar == 0)
+    {
+      isFirstLog = false;
+      return;
+    }
+  std::string env = envVar;
+  if (env == "print-list")
+    {
+      LogComponentPrintList ();
+      isFirstLog = false;
+      return;
+    }
+  bool allFound = true;
+  std::string::size_type cur = 0;
+  std::string::size_type next = 0;
+  while (true)
+    {
+      next = env.find_first_of (";", cur);
+      std::string tmp = std::string (env, cur, next);
+      {
+        /* The following code is a workaround for a bug in the g++
+         * c++ string library. Its goal is to remove any trailing ';'
+         * from the string even though there should not be any in
+         * it. This code should be safe even if the bug is not there.
+         */
+        std::string::size_type trailing = tmp.find_first_of (";");
+        tmp = tmp.substr (0, trailing);
+      }
+      if (tmp.size () == 0)
+        {
+          break;
+        }
+      std::string::size_type equal = tmp.find ("=");
+      std::string component;
+      int level;
+      if (equal == std::string::npos)
+        {
+          component = tmp;
+          level = LOG_DEBUG;
+        }
+      else
+        {
+          component = tmp.substr (0, equal);
+          std::string::size_type cur_lev;
+          std::string::size_type next_lev = equal;
+          do
+            {
+              cur_lev = next_lev + 1;
+              next_lev = tmp.find ("|", cur_lev);
+              std::string lev = tmp.substr (cur_lev, next_lev - cur_lev);
+              if (lev == "error")
+                {
+                  level |= LOG_ERROR;
+                }
+              else if (lev == "warn")
+                {
+                  level |= LOG_WARN;
+                }
+              else if (lev == "debug")
+                {
+                  level |= LOG_DEBUG;
+                }
+              else if (lev == "info")
+                {
+                  level |= LOG_INFO;
+                }
+              else if (lev == "function")
+                {
+                  level |= LOG_FUNCTION;
+                }
+              else if (lev == "param")
+                {
+                  level |= LOG_PARAM;
+                }
+              else if (lev == "logic")
+                {
+                  level |= LOG_LOGIC;
+                }
+              else if (lev == "all")
+                {
+                  level |= LOG_ALL;
+                }
+              else if (lev == "errorlevel")
+                {
+                  level |= LOG_LEVEL_ERROR;
+                }
+              else if (lev == "warnlevel")
+                {
+                  level |= LOG_LEVEL_WARN;
+                }
+              else if (lev == "debuglevel")
+                {
+                  level |= LOG_LEVEL_DEBUG;
+                }
+              else if (lev == "infolevel")
+                {
+                  level |= LOG_LEVEL_INFO;
+                }
+              else if (lev == "functionlevel")
+                {
+                  level |= LOG_LEVEL_FUNCTION;
+                }
+              else if (lev == "paramlevel")
+                {
+                  level |= LOG_LEVEL_PARAM;
+                }
+              else if (lev == "logiclevel")
+                {
+                  level |= LOG_LEVEL_LOGIC;
+                }
+              else if (lev == "alllevel")
+                {
+                  level |= LOG_LEVEL_ALL;
+                }
+            } while (next_lev != std::string::npos);
+        }
+      bool found = false;
+      ComponentList *components = GetComponentList ();
+      for (ComponentListI i = components->begin ();
+           i != components->end ();
+           i++)
+        {
+          if (i->first.compare (component) == 0)
+            {
+              found = true;
+              
+              i->second->Enable ((enum LogLevel)level);
+              break;
+            }
+        }
+      if (!found)
+        {
+          allFound = false;
+        }
+      if (next == std::string::npos)
+        {
+          break;
+        }
+      cur = next + 1;
+      if (cur >= env.size ()) 
+        {
+          break;
+        }
+    }
+  if (allFound)
+    {
+      isFirstLog = false;
+    }
+  
+#endif
+}
+
+LogComponent::LogComponent (char const * name)
+  : m_levels (0)
+{
+  ComponentList *components = GetComponentList ();
+  for (ComponentListI i = components->begin ();
+       i != components->end ();
+       i++)
+    {
+      NS_ASSERT (i->first != name);
+    }
+  components->push_back (std::make_pair (name, this));
+}
+
+bool 
+LogComponent::IsEnabled (enum LogLevel level) const
+{
+  LogComponentEnableEnvVar ();
+  return (level & m_levels) ? 1 : 0;
+}
+
+bool
+LogComponent::IsNoneEnabled (void) const
+{
+  return m_levels == 0;
+}
+
+void 
+LogComponent::Enable (enum LogLevel level)
+{
+  m_levels |= level;
+}
+
+void 
+LogComponent::Disable (enum LogLevel level)
+{
+  m_levels &= ~level;
+}
+
+void 
+LogComponentEnable (char const *name, enum LogLevel level)
+{
+  ComponentList *components = GetComponentList ();
+  for (ComponentListI i = components->begin ();
+       i != components->end ();
+       i++)
+    {
+      if (i->first.compare (name) == 0) 
+	{
+	  i->second->Enable (level);
+	  break;
+	}
+    }  
+}
+
+void 
+LogComponentDisable (char const *name, enum LogLevel level)
+{
+  ComponentList *components = GetComponentList ();
+  for (ComponentListI i = components->begin ();
+       i != components->end ();
+       i++)
+    {
+      if (i->first.compare (name) == 0) 
+	{
+	  i->second->Disable (level);
+	  break;
+	}
+    }  
+}
+
+void 
+LogComponentPrintList (void)
+{
+  ComponentList *components = GetComponentList ();
+  for (ComponentListI i = components->begin ();
+       i != components->end ();
+       i++)
+    {
+      std::cout << i->first << "=";
+      if (i->second->IsNoneEnabled ())
+        {
+          std::cout << "0" << std::endl;
+          continue;
+        }
+      if (i->second->IsEnabled (LOG_ERROR))
+        {
+          std::cout << "error";
+        }
+      if (i->second->IsEnabled (LOG_WARN))
+        {
+          std::cout << "|warn";
+        }
+      if (i->second->IsEnabled (LOG_DEBUG))
+        {
+          std::cout << "|debug";
+        }
+      if (i->second->IsEnabled (LOG_INFO))
+        {
+          std::cout << "|info";
+        }
+      if (i->second->IsEnabled (LOG_FUNCTION))
+        {
+          std::cout << "|function";
+        }
+      if (i->second->IsEnabled (LOG_PARAM))
+        {
+          std::cout << "|param";
+        }
+      if (i->second->IsEnabled (LOG_LOGIC))
+        {
+          std::cout << "|logic";
+        }
+      if (i->second->IsEnabled (LOG_ALL))
+        {
+          std::cout << "|all";
+        }
+      std::cout << std::endl;
+    }
+}
+
+} // namespace ns3
+
+#endif // NS3_LOG_ENABLE
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/log.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,251 @@
+/* -*- 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 __LOG_H__
+#define __LOG_H__
+
+#include <string>
+#include <iostream>
+
+/**
+ * \defgroup logging Logging
+ * \brief Logging functions and macros
+ *
+ *   LOG functionality: macros which allow developers to
+ *     send information out on screen. All logging messages 
+ *     are disabled by default. To enable selected logging 
+ *     messages, use the ns3::LogComponentEnable
+ *     function. 
+ * 
+ * Alternatively, you can use the NS_LOG
+ * environment variable to define a ';'-separated list of
+ * logging components to enable. For example, NS_LOG=a;b;c;DAFD;GH
+ * would enable the components 'a', 'b', 'c', 'DAFD', and, 'GH'.
+ *
+ * For each component, the "debug" log level is enabled by default
+ * but more components can be enabled selectively with the following
+ * syntax: NS_LOG='Component1=func|param|warn;Component2=error|debug'
+ * This example would enable the 'func', 'param', and 'warn' log
+ * levels for 'Component1' and the 'error' and 'debug' log levels
+ * for 'Component2'.
+ *
+ * The list of available log components can be printed on stdout
+ * with the NS_LOG=print-list syntax.
+ */
+
+/**
+ * \ingroup logging
+ * \param name a string
+ *
+ * Define a Log component with a specific name. This macro
+ * should be used at the top of every file in which you want 
+ * to use the NS_LOG macro. This macro defines a new
+ * "log component" which can be later selectively enabled
+ * or disabled with the ns3::LogComponentEnable and 
+ * ns3::LogComponentDisable functions or with the NS_LOG
+ * environment variable.
+ */
+
+#ifdef NS3_LOG_ENABLE
+
+#define NS_LOG_COMPONENT_DEFINE(name)                                \
+  static ns3::LogComponent g_log = ns3::LogComponent (name)
+
+#else
+
+#define NS_LOG_COMPONENT_DEFINE(name)
+
+#endif
+
+/**
+ * \ingroup logging
+ * \param msg message to output
+ *
+ * Generate logging output in the "log component" of the 
+ * current file. i.e., every call to NS_LOG from within
+ * a file implicitely generates out within the component
+ * defined with the NS_LOG_COMPONENT_DEFINE macro in the
+ * same file.
+ */
+
+#ifdef NS3_LOG_ENABLE
+
+#define NS_LOG(level, msg)                                      \
+  do                                                            \
+    {                                                           \
+      if (g_log.IsEnabled (level))                              \
+        {                                                       \
+          std::clog << __PRETTY_FUNCTION__ << " ==> " <<        \
+            msg << std::endl;                                   \
+        }                                                       \
+    }                                                           \
+  while (false)
+
+#define NS_LOG_F(level)                                 \
+  do                                                    \
+    {                                                   \
+      if (g_log.IsEnabled (level))                      \
+        {                                               \
+          std::clog << __PRETTY_FUNCTION__ << std::endl;\
+        }                                               \
+    }                                                   \
+  while (false)
+
+#define NS_LOG_ERROR(msg) \
+  NS_LOG(ns3::LOG_ERROR, msg)
+
+#define NS_LOG_WARN(msg) \
+  NS_LOG(ns3::LOG_WARN, msg)
+
+#define NS_LOG_DEBUG(msg) \
+  NS_LOG(ns3::LOG_DEBUG, msg)
+
+#define NS_LOG_INFO(msg) \
+  NS_LOG(ns3::LOG_INFO, msg)
+
+#define NS_LOG_FUNCTION \
+  NS_LOG_F(ns3::LOG_FUNCTION)
+
+#define NS_LOG_PARAM(msg) \
+  NS_LOG(ns3::LOG_PARAM, msg)
+
+#define NS_LOG_LOGIC(msg) \
+  NS_LOG(ns3::LOG_LOGIC, msg)
+
+#define NS_LOG_ALL(msg) \
+  NS_LOG(ns3::LOG_ALL, msg)
+
+#define NS_LOG_UNCOND(msg)              \
+  do                                    \
+    {                                   \
+      std::clog << msg << std::endl;    \
+    }                                   \
+  while (false)
+
+#else
+
+#define NS_LOG(level, msg)
+#define NS_LOG_F(level)
+#define NS_LOG_ERROR(msg)
+#define NS_LOG_WARN(msg)
+#define NS_LOG_DEBUG(msg)
+#define NS_LOG_INFO(msg)
+#define NS_LOG_FUNCTION
+#define NS_LOG_PARAM(msg)
+#define NS_LOG_LOGIC(msg)
+#define NS_LOG_ALL(msg)
+#define NS_LOG_UNCOND(msg)
+
+#endif
+
+namespace ns3 {
+
+#ifdef NS3_LOG_ENABLE
+
+enum LogLevel {
+  LOG_ERROR          = 0x0001, // serious error messages only
+  LOG_LEVEL_ERROR    = 0x0001,
+
+  LOG_WARN           = 0x0002, // warning messages
+  LOG_LEVEL_WARN     = 0x0003,
+
+  LOG_DEBUG          = 0x0004, // rare ad-hoc debug messages
+  LOG_LEVEL_DEBUG    = 0x0007,
+
+  LOG_INFO           = 0x0008, // informational messages (e.g., banners)
+  LOG_LEVEL_INFO     = 0x000f,
+
+  LOG_FUNCTION       = 0x0010, // function tracing
+  LOG_LEVEL_FUNCTION = 0x001f, 
+
+  LOG_PARAM          = 0x0020, // parameters to functions
+  LOG_LEVEL_PARAM    = 0x003f,
+
+  LOG_LOGIC          = 0x0040, // control flow tracing within functions
+  LOG_LEVEL_LOGIC    = 0x007f,
+
+  LOG_ALL            = 0x4000, // print everything
+  LOG_LEVEL_ALL      = 0x7fff
+};
+
+#endif
+
+/**
+ * \param name a log component name
+ * \ingroup logging
+ *
+ * Enable the logging output associated with that log component.
+ * The logging output can be later disabled with a call
+ * to ns3::LogComponentDisable.
+ */
+#ifdef NS3_LOG_ENABLE
+void LogComponentEnable (char const *name, enum LogLevel level);
+#else
+#define LogComponentEnable(a,b)
+#endif
+
+/**
+ * \param name a log component name
+ * \ingroup logging
+ *
+ * Disable the logging output associated with that log component.
+ * The logging output can be later re-enabled with a call
+ * to ns3::LogComponentEnable.
+ */
+#ifdef NS3_LOG_ENABLE
+void LogComponentDisable (char const *name, enum LogLevel level);
+#else
+#define LogComponentDisable(a,b)
+#endif
+
+/**
+ * \ingroup logging
+ *
+ * Print the list of logging messages available.
+ * The output of this function can be obtained by setting
+ * the NS_LOG environment variable to the special value 
+ * 'print-list'.
+ * 
+ * For example: NS_LOG=print-list
+ */
+#ifdef NS3_LOG_ENABLE
+void LogComponentPrintList (void);
+#else
+#define LogComponentPrintList()
+#endif
+
+#ifdef NS3_LOG_ENABLE
+
+class LogComponent {
+public:
+  LogComponent (char const *name);
+  bool IsEnabled (enum LogLevel level) const;
+  bool IsNoneEnabled (void) const;
+  void Enable (enum LogLevel level);
+  void Disable (enum LogLevel level);
+private:
+  int32_t m_levels;
+};
+
+#endif
+
+} // namespace ns3
+
+#endif // __LOG_H__
--- a/src/core/object.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/object.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -22,8 +22,12 @@
 #include "assert.h"
 #include "singleton.h"
 #include "uid-manager.h"
+#include "trace-resolver.h"
+#include "log.h"
 #include <vector>
 
+NS_LOG_COMPONENT_DEFINE ("Object");
+
 namespace {
 
 class IidManager : public ns3::UidManager
@@ -34,6 +38,7 @@
 public:
   void SetParent (uint16_t child, const uint16_t *parent);
   uint16_t LookupParent (uint16_t child);
+
 private:
   std::vector<const uint16_t *> m_parents;
 };
@@ -55,6 +60,68 @@
 
 namespace ns3 {
 
+class InterfaceIdTraceResolver : public TraceResolver
+{
+public:
+  InterfaceIdTraceResolver (Ptr<const Object> aggregate);
+  virtual void Connect (std::string path, CallbackBase const &cb, const TraceContext &context);
+  virtual void Disconnect (std::string path, CallbackBase const &cb);
+  virtual void CollectSources (std::string path, const TraceContext &context, 
+                               SourceCollection *collection);
+  virtual void TraceAll (std::ostream &os, const TraceContext &context);
+private:
+  Ptr<const Object> ParseForInterface (std::string path);
+  Ptr<const Object> m_aggregate;
+};
+
+InterfaceIdTraceResolver::InterfaceIdTraceResolver (Ptr<const Object> aggregate)
+  : m_aggregate (aggregate)
+{}
+Ptr<const Object>
+InterfaceIdTraceResolver::ParseForInterface (std::string path)
+{
+  std::string element = GetElement (path);
+  std::string::size_type dollar_pos = element.find ("$");
+  if (dollar_pos != 0)
+    {
+      return 0;
+    }
+  std::string interfaceName = element.substr (1, std::string::npos);
+  InterfaceId interfaceId = InterfaceId::LookupByName (interfaceName);
+  Ptr<Object> interface = m_aggregate->QueryInterface<Object> (interfaceId);
+  return interface;
+}
+void 
+InterfaceIdTraceResolver::Connect (std::string path, CallbackBase const &cb, const TraceContext &context)
+{
+  Ptr<const Object> interface = ParseForInterface (path);
+  if (interface != 0)
+    {
+      interface->GetTraceResolver ()->Connect (GetSubpath (path), cb, context);
+    }
+}
+void 
+InterfaceIdTraceResolver::Disconnect (std::string path, CallbackBase const &cb)
+{
+  Ptr<const Object> interface = ParseForInterface (path);
+  if (interface != 0)
+    {
+      interface->TraceDisconnect (GetSubpath (path), cb);
+    }
+}
+void 
+InterfaceIdTraceResolver::CollectSources (std::string path, const TraceContext &context, 
+                                          SourceCollection *collection)
+{
+  m_aggregate->DoCollectSources (path, context, collection);
+}
+void 
+InterfaceIdTraceResolver::TraceAll (std::ostream &os, const TraceContext &context)
+{
+  m_aggregate->DoTraceAll (os, context);
+}
+
+
 InterfaceId::InterfaceId (uint16_t iid)
   : m_iid (iid)
 {}
@@ -72,6 +139,12 @@
 {
   return Singleton<IidTree>::Get ()->LookupParent (iid.m_iid);
 }
+std::string 
+InterfaceId::GetName (void) const
+{
+  std::string name = Singleton<IidManager>::Get ()->LookupByUid (m_iid);
+  return name;
+}
 
 bool operator == (const InterfaceId &a, const InterfaceId &b)
 {
@@ -109,6 +182,7 @@
   : m_count (1),
     m_iid (Object::iid),
     m_disposed (false),
+    m_collecting (false),
     m_next (this)
 {}
 Object::~Object () 
@@ -163,6 +237,17 @@
 }
 
 void 
+Object::TraceConnect (std::string path, const CallbackBase &cb) const
+{
+  GetTraceResolver ()->Connect (path, cb, TraceContext ());
+}
+void 
+Object::TraceDisconnect (std::string path, const CallbackBase &cb) const
+{
+  GetTraceResolver ()->Disconnect (path, cb);
+}
+
+void 
 Object::SetInterfaceId (InterfaceId iid)
 {
   NS_ASSERT (Check ());
@@ -175,6 +260,14 @@
   NS_ASSERT (!m_disposed);
 }
 
+Ptr<TraceResolver>
+Object::GetTraceResolver (void) const
+{
+  Ptr<InterfaceIdTraceResolver> resolver =
+    Create<InterfaceIdTraceResolver> (this);
+  return resolver;
+}
+
 bool 
 Object::Check (void) const
 {
@@ -208,12 +301,77 @@
   } while (current != end);
 }
 
+void 
+Object::DoCollectSources (std::string path, const TraceContext &context, 
+                          TraceResolver::SourceCollection *collection) const
+{
+  const Object *current;
+  current = this;
+  do {
+    if (current->m_collecting)
+      {
+        return;
+      }
+    current = current->m_next;
+  } while (current != this);
+
+  m_collecting = true;
+
+  current = this->m_next;
+  while (current != this)
+    {
+      NS_ASSERT (current != 0);
+      NS_LOG_LOGIC ("collect current=" << current);
+      InterfaceId cur = current->m_iid;
+      while (cur != Object::iid)
+        {
+          std::string name = cur.GetName ();
+          std::string fullpath = path;
+          fullpath.append ("/$");
+          fullpath.append (name);
+          NS_LOG_LOGIC("collect: " << fullpath);
+          current->GetTraceResolver ()->CollectSources (fullpath, context, collection);
+          cur = InterfaceId::LookupParent (cur);
+        }
+      current = current->m_next;
+    }
+
+  m_collecting = false;
+}
+void 
+Object::DoTraceAll (std::ostream &os, const TraceContext &context) const
+{
+  const Object *current;
+  current = this;
+  do {
+    if (current->m_collecting)
+      {
+        return;
+      }
+    current = current->m_next;
+  } while (current != this);
+
+  m_collecting = true;
+
+  current = this->m_next;
+  while (current != this)
+    {
+      NS_ASSERT (current != 0);
+      current->GetTraceResolver ()->TraceAll (os, context);
+      current = current->m_next;
+    }
+
+  m_collecting = false;
+}
+
 } // namespace ns3
 
 
 #ifdef RUN_SELF_TESTS
 
 #include "test.h"
+#include "sv-trace-source.h"
+#include "composite-trace-resolver.h"
 
 namespace {
 
@@ -225,7 +383,18 @@
   {
     SetInterfaceId (BaseA::iid);
   }
+  void BaseGenerateTrace (int16_t v)
+  { m_source = v; }
   virtual void Dispose (void) {}
+  virtual ns3::Ptr<ns3::TraceResolver> GetTraceResolver (void) const
+  {
+    ns3::Ptr<ns3::CompositeTraceResolver> resolver = 
+      ns3::Create<ns3::CompositeTraceResolver> ();
+    resolver->AddSource ("basea-x", ns3::TraceDoc ("test source"), m_source);
+    resolver->SetParentResolver (Object::GetTraceResolver ());
+    return resolver;
+  }
+  ns3::SVTraceSource<int16_t> m_source;
 };
 
 class DerivedA : public BaseA
@@ -236,9 +405,20 @@
   {
     SetInterfaceId (DerivedA::iid);
   }
+  void DerivedGenerateTrace (int16_t v)
+  { m_sourceDerived = v; }
   virtual void Dispose (void) {
     BaseA::Dispose ();
   }
+  virtual ns3::Ptr<ns3::TraceResolver> GetTraceResolver (void) const
+  {
+    ns3::Ptr<ns3::CompositeTraceResolver> resolver = 
+      ns3::Create<ns3::CompositeTraceResolver> ();
+    resolver->AddSource ("deriveda-x", ns3::TraceDoc ("test source"), m_sourceDerived);
+    resolver->SetParentResolver (BaseA::GetTraceResolver ());
+    return resolver;
+  }
+  ns3::SVTraceSource<int16_t> m_sourceDerived;
 };
 
 const ns3::InterfaceId BaseA::iid = 
@@ -254,7 +434,18 @@
   {
     SetInterfaceId (BaseB::iid);
   }
+  void BaseGenerateTrace (int16_t v)
+  { m_source = v; }
   virtual void Dispose (void) {}
+  virtual ns3::Ptr<ns3::TraceResolver> GetTraceResolver (void) const
+  {
+    ns3::Ptr<ns3::CompositeTraceResolver> resolver = 
+      ns3::Create<ns3::CompositeTraceResolver> ();
+    resolver->AddSource ("baseb-x", ns3::TraceDoc ("test source"), m_source);
+    resolver->SetParentResolver (Object::GetTraceResolver ());
+    return resolver;
+  }
+  ns3::SVTraceSource<int16_t> m_source;
 };
 
 class DerivedB : public BaseB
@@ -265,9 +456,20 @@
   {
     SetInterfaceId (DerivedB::iid);
   }
+  void DerivedGenerateTrace (int16_t v)
+  { m_sourceDerived = v; }
   virtual void Dispose (void) {
     BaseB::Dispose ();
   }
+  virtual ns3::Ptr<ns3::TraceResolver> GetTraceResolver (void) const
+  {
+    ns3::Ptr<ns3::CompositeTraceResolver> resolver = 
+      ns3::Create<ns3::CompositeTraceResolver> ();
+    resolver->AddSource ("derivedb-x", ns3::TraceDoc ("test source"), m_sourceDerived);
+    resolver->SetParentResolver (BaseB::GetTraceResolver ());
+    return resolver;
+  }
+  ns3::SVTraceSource<int16_t> m_sourceDerived;
 };
 
 const ns3::InterfaceId BaseB::iid = 
@@ -284,120 +486,82 @@
 public:
   ObjectTest ();
   virtual bool RunTests (void);
+private:
+  void BaseATrace (const TraceContext &context, int64_t oldValue, int64_t newValue);
+  void DerivedATrace (const TraceContext &context, int64_t oldValue, int64_t newValue);
+  void BaseBTrace (const TraceContext &context, int64_t oldValue, int64_t newValue);
+  void DerivedBTrace (const TraceContext &context, int64_t oldValue, int64_t newValue);
+
+  bool m_baseATrace;
+  bool m_derivedATrace;
+  bool m_baseBTrace;
+  bool m_derivedBTrace;
 };
 
 ObjectTest::ObjectTest ()
   : Test ("Object")
 {}
+void 
+ObjectTest::BaseATrace (const TraceContext &context, int64_t oldValue, int64_t newValue)
+{
+  m_baseATrace = true;
+}
+void 
+ObjectTest::DerivedATrace (const TraceContext &context, int64_t oldValue, int64_t newValue)
+{
+  m_derivedATrace = true;
+}
+void 
+ObjectTest::BaseBTrace (const TraceContext &context, int64_t oldValue, int64_t newValue)
+{
+  m_baseBTrace = true;
+}
+void 
+ObjectTest::DerivedBTrace (const TraceContext &context, int64_t oldValue, int64_t newValue)
+{
+  m_derivedBTrace = true;
+}
+
 bool 
 ObjectTest::RunTests (void)
 {
-  bool ok = true;
+  bool result = true;
 
   Ptr<BaseA> baseA = Create<BaseA> ();
-  if (baseA->QueryInterface<BaseA> (BaseA::iid) != baseA)
-    {
-      ok = false;
-    }
-  if (baseA->QueryInterface<BaseA> (DerivedA::iid) != 0)
-    {
-      ok = false;
-    }
-  if (baseA->QueryInterface<DerivedA> (DerivedA::iid) != 0)
-    {
-      ok = false;
-    }
+  NS_TEST_ASSERT_EQUAL (baseA->QueryInterface<BaseA> (BaseA::iid), baseA);
+  NS_TEST_ASSERT_EQUAL (baseA->QueryInterface<BaseA> (DerivedA::iid), 0);
+  NS_TEST_ASSERT_EQUAL (baseA->QueryInterface<DerivedA> (DerivedA::iid), 0);
   baseA = Create<DerivedA> (10);
-  if (baseA->QueryInterface<BaseA> (BaseA::iid) != baseA)
-    {
-      ok = false;
-    }
-  if (baseA->QueryInterface<BaseA> (DerivedA::iid) != baseA)
-    {
-      ok = false;
-    }
-  if (baseA->QueryInterface<DerivedA> (DerivedA::iid) == 0)
-    {
-      ok = false;
-    }
+  NS_TEST_ASSERT_EQUAL (baseA->QueryInterface<BaseA> (BaseA::iid), baseA);
+  NS_TEST_ASSERT_EQUAL (baseA->QueryInterface<BaseA> (DerivedA::iid), baseA);
+  NS_TEST_ASSERT_UNEQUAL (baseA->QueryInterface<DerivedA> (DerivedA::iid), 0);
 
   baseA = Create<BaseA> ();
   Ptr<BaseB> baseB = Create<BaseB> ();
   Ptr<BaseB> baseBCopy = baseB;
   baseA->AddInterface (baseB);
-  if (baseA->QueryInterface<BaseA> (BaseA::iid) == 0)
-    {
-      ok = false;
-    }
-  if (baseA->QueryInterface<DerivedA> (DerivedA::iid) != 0)
-    {
-      ok = false;
-    }
-  if (baseA->QueryInterface<BaseB> (BaseB::iid) == 0)
-    {
-      ok = false;
-    }
-  if (baseA->QueryInterface<DerivedB> (DerivedB::iid) != 0)
-    {
-      ok = false;
-    }
-  if (baseB->QueryInterface<BaseB> (BaseB::iid) == 0)
-    {
-      ok = false;
-    }
-  if (baseB->QueryInterface<DerivedB> (DerivedB::iid) != 0)
-    {
-      ok = false;
-    }
-  if (baseB->QueryInterface<BaseA> (BaseA::iid) == 0)
-    {
-      ok = false;
-    }
-  if (baseB->QueryInterface<DerivedA> (DerivedA::iid) != 0)
-    {
-      ok = false;
-    }
-  if (baseBCopy->QueryInterface<BaseA> (BaseA::iid) == 0)
-    {
-      ok = false;
-    }
+  NS_TEST_ASSERT_UNEQUAL (baseA->QueryInterface<BaseA> (BaseA::iid), 0);
+  NS_TEST_ASSERT_EQUAL (baseA->QueryInterface<DerivedA> (DerivedA::iid), 0);
+  NS_TEST_ASSERT_UNEQUAL (baseA->QueryInterface<BaseB> (BaseB::iid), 0);
+  NS_TEST_ASSERT_EQUAL (baseA->QueryInterface<DerivedB> (DerivedB::iid), 0);
+  NS_TEST_ASSERT_UNEQUAL (baseB->QueryInterface<BaseB> (BaseB::iid), 0);
+  NS_TEST_ASSERT_EQUAL (baseB->QueryInterface<DerivedB> (DerivedB::iid), 0);
+  NS_TEST_ASSERT_UNEQUAL (baseB->QueryInterface<BaseA> (BaseA::iid), 0);
+  NS_TEST_ASSERT_EQUAL (baseB->QueryInterface<DerivedA> (DerivedA::iid), 0);
+  NS_TEST_ASSERT_UNEQUAL (baseBCopy->QueryInterface<BaseA> (BaseA::iid), 0);
 
   baseA = Create<DerivedA> (1);
   baseB = Create<DerivedB> (1);
   baseBCopy = baseB;
   baseA->AddInterface (baseB);
-  if (baseA->QueryInterface<DerivedB> (DerivedB::iid) == 0)
-    {
-      ok = false;
-    }
-  if (baseA->QueryInterface<BaseB> (BaseB::iid) == 0)
-    {
-      ok = false;
-    }
-  if (baseB->QueryInterface<DerivedA> (DerivedA::iid) == 0)
-    {
-      ok = false;
-    }
-  if (baseB->QueryInterface<BaseA> (BaseA::iid) == 0)
-    {
-      ok = false;
-    }
-  if (baseBCopy->QueryInterface<DerivedA> (DerivedA::iid) == 0)
-    {
-      ok = false;
-    }
-  if (baseBCopy->QueryInterface<BaseA> (BaseA::iid) == 0)
-    {
-      ok = false;
-    }
-  if (baseB->QueryInterface<DerivedB> (DerivedB::iid) == 0)
-    {
-      ok = false;
-    }
-  if (baseB->QueryInterface<BaseB> (BaseB::iid) == 0)
-    {
-      ok = false;
-    }
+  NS_TEST_ASSERT_UNEQUAL (baseA->QueryInterface<DerivedB> (DerivedB::iid), 0);
+  NS_TEST_ASSERT_UNEQUAL (baseA->QueryInterface<BaseB> (BaseB::iid), 0);
+  NS_TEST_ASSERT_UNEQUAL (baseB->QueryInterface<DerivedA> (DerivedA::iid), 0);
+  NS_TEST_ASSERT_UNEQUAL (baseB->QueryInterface<BaseA> (BaseA::iid), 0);
+  NS_TEST_ASSERT_UNEQUAL (baseBCopy->QueryInterface<DerivedA> (DerivedA::iid), 0);
+  NS_TEST_ASSERT_UNEQUAL (baseBCopy->QueryInterface<BaseA> (BaseA::iid), 0);
+  NS_TEST_ASSERT_UNEQUAL (baseB->QueryInterface<DerivedB> (DerivedB::iid), 0);
+  NS_TEST_ASSERT_UNEQUAL (baseB->QueryInterface<BaseB> (BaseB::iid), 0)
 
   baseA = Create<BaseA> ();
   baseB = Create<BaseB> ();
@@ -405,7 +569,76 @@
   baseA = 0;
   baseA = baseB->QueryInterface<BaseA> (BaseA::iid);
 
-  return ok;
+  baseA = Create<BaseA> ();
+  baseA->TraceConnect ("/basea-x", MakeCallback (&ObjectTest::BaseATrace, this));
+  m_baseATrace = false;
+  baseA->BaseGenerateTrace (1);
+  NS_TEST_ASSERT (m_baseATrace);
+  baseA->TraceDisconnect ("/basea-x", MakeCallback (&ObjectTest::BaseATrace, this));
+
+  baseB = Create<BaseB> ();
+  baseB->TraceConnect ("/baseb-x",  MakeCallback (&ObjectTest::BaseBTrace, this));
+  m_baseBTrace = false;
+  baseB->BaseGenerateTrace (2);
+  NS_TEST_ASSERT (m_baseBTrace);
+  baseB->TraceDisconnect ("/baseb-x",  MakeCallback (&ObjectTest::BaseBTrace, this));
+
+  baseA->AddInterface (baseB);
+
+  baseA->TraceConnect ("/basea-x", MakeCallback (&ObjectTest::BaseATrace, this));
+  m_baseATrace = false;
+  baseA->BaseGenerateTrace (3);
+  NS_TEST_ASSERT (m_baseATrace);
+  baseA->TraceDisconnect ("/basea-x", MakeCallback (&ObjectTest::BaseATrace, this));
+
+  baseA->TraceConnect ("/$BaseB/baseb-x",  MakeCallback (&ObjectTest::BaseBTrace, this));
+  m_baseBTrace = false;
+  baseB->BaseGenerateTrace (4);
+  NS_TEST_ASSERT (m_baseBTrace);
+  baseA->TraceDisconnect ("/$BaseB/baseb-x",  MakeCallback (&ObjectTest::BaseBTrace, this));
+  m_baseBTrace = false;
+  baseB->BaseGenerateTrace (5);
+  NS_TEST_ASSERT (!m_baseBTrace);
+
+  baseB->TraceConnect ("/$BaseA/basea-x", MakeCallback (&ObjectTest::BaseATrace, this));
+  m_baseATrace = false;
+  baseA->BaseGenerateTrace (6);
+  NS_TEST_ASSERT (m_baseATrace);
+  baseB->TraceDisconnect ("/$BaseA/basea-x", MakeCallback (&ObjectTest::BaseATrace, this));
+
+  baseA->TraceConnect ("/$BaseA/basea-x", MakeCallback (&ObjectTest::BaseATrace, this));
+  m_baseATrace = false;
+  baseA->BaseGenerateTrace (7);
+  NS_TEST_ASSERT (m_baseATrace);
+  baseA->TraceDisconnect ("/$BaseA/basea-x", MakeCallback (&ObjectTest::BaseATrace, this));
+
+  Ptr<DerivedA> derivedA;
+  derivedA = Create<DerivedA> (1);
+  baseB = Create<BaseB> ();
+  derivedA->AddInterface (baseB);
+  baseB->TraceConnect ("/$DerivedA/deriveda-x", MakeCallback (&ObjectTest::DerivedATrace, this));
+  baseB->TraceConnect ("/$DerivedA/basea-x", MakeCallback (&ObjectTest::BaseATrace, this));
+  m_derivedATrace = false;
+  m_baseATrace = false;
+  derivedA->DerivedGenerateTrace (8);
+  derivedA->BaseGenerateTrace (9);
+  NS_TEST_ASSERT (m_derivedATrace);
+  NS_TEST_ASSERT (m_baseATrace);
+  baseB->TraceDisconnect ("/$DerivedA/deriveda-x", MakeCallback (&ObjectTest::BaseATrace, this));
+  baseB->TraceDisconnect ("/$DerivedA/basea-x", MakeCallback (&ObjectTest::BaseATrace, this));
+
+  baseB->TraceConnect ("/$DerivedA/*", MakeCallback (&ObjectTest::DerivedATrace, this));
+  m_derivedATrace = false;
+  derivedA->DerivedGenerateTrace (10);
+  NS_TEST_ASSERT (m_derivedATrace);
+  // here, we have connected the derived trace sink to all 
+  // trace sources, including the base trace source.
+  m_derivedATrace = false;
+  derivedA->BaseGenerateTrace (11);
+  NS_TEST_ASSERT (m_derivedATrace);
+  baseB->TraceDisconnect ("/$DerivedA/*", MakeCallback (&ObjectTest::BaseATrace, this));
+
+  return result;
 }
 
 static ObjectTest g_interfaceObjectTests;
--- a/src/core/object.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/object.h	Fri Sep 28 11:59:46 2007 +0100
@@ -24,9 +24,13 @@
 #include <stdint.h>
 #include <string>
 #include "ptr.h"
+#include "trace-resolver.h"
 
 namespace ns3 {
 
+class TraceContext;
+class CallbackBase;
+
 /**
  * \brief a unique identifier for an interface.
  *
@@ -56,6 +60,11 @@
    * id is not a valid interface id.
    */
   static InterfaceId LookupParent (InterfaceId iid);
+
+  /**
+   * \returns the name of this interface.
+   */
+  std::string GetName (void) const;
   ~InterfaceId ();
 private:
   InterfaceId (uint16_t iid);
@@ -131,6 +140,30 @@
    * on one to get the other, and vice-versa. 
    */
   void AddInterface (Ptr<Object> other);
+
+  /**
+   * \param path the path to match for the callback
+   * \param cb callback to connect
+   *
+   * Connect the input callback to all trace sources which
+   * match the input path.
+   *
+   */
+  void TraceConnect (std::string path, const CallbackBase &cb) const;
+  /**
+   * \param path the path to match for the callback
+   * \param cb callback to disconnect
+   *
+   * Disconnect the input callback from all trace sources which
+   * match the input path.
+   */
+  void TraceDisconnect (std::string path, const CallbackBase &cb) const;
+  /**
+   * \returns the trace resolver associated to this object.
+   *
+   * This method should be rarely called by users.
+   */
+  virtual Ptr<TraceResolver> GetTraceResolver (void) const;
 protected:
   /**
    * \param iid an InterfaceId
@@ -147,12 +180,17 @@
    */
   virtual void DoDispose (void);
 private:
+  friend class InterfaceIdTraceResolver;
   Ptr<Object> DoQueryInterface (InterfaceId iid) const;
+  void DoCollectSources (std::string path, const TraceContext &context, 
+                         TraceResolver::SourceCollection *collection) const;
+  void DoTraceAll (std::ostream &os, const TraceContext &context) const;
   bool Check (void) const;
   void MaybeDelete (void) const;
   mutable uint32_t m_count;
   InterfaceId m_iid;
   bool m_disposed;
+  mutable bool m_collecting;
   Object *m_next;
 };
 
--- a/src/core/ptr.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/ptr.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -28,9 +28,14 @@
 
 namespace ns3 {
 
+template <typename T>
+void Foo (void) {}
+
+
 class NoCount : public Object
 {
 public:
+  NoCount (void (*fn) (void));
   NoCount (Callback<void> cb);
   ~NoCount ();
   void Nothing (void) const;
@@ -292,12 +297,22 @@
     callback ();
   }
 
+
 #if 0
   // as expected, fails compilation.
   {
     Ptr<const Object> p = Create<NoCount> (cb);
     Callback<void> callback = MakeCallback (&NoCount::Nothing, p);
   }
+  // local types are not allowed as arguments to a template.
+  {
+    class B
+    {
+    public:
+      B () {}
+    };
+    Foo<B> ();
+  }
 #endif
   
 
--- a/src/core/ptr.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/ptr.h	Fri Sep 28 11:59:46 2007 +0100
@@ -22,6 +22,7 @@
 #ifndef PTR_H
 #define PTR_H
 
+#include <iostream>
 #include <stdint.h>
 #include "assert.h"
 
@@ -64,7 +65,7 @@
   template <typename U>
   friend U *PeekPointer (const Ptr<U> &p);
 
-  void Acquire (void) const;
+  inline void Acquire (void) const;
 public:
   /**
    * Create an empty smart pointer
@@ -80,7 +81,16 @@
    * same, so that object is deleted if no more references to it
    * remain.
    */
-  Ptr (T *ptr);
+  Ptr (T *ptr);  
+  /**
+   * \param ptr raw pointer to manage
+   * \param ref if set to true, this method calls Ref, otherwise,
+   *        it does not call Ref.
+   *    
+   * Create a smart pointer which points to the object pointed to by
+   * the input raw pointer ptr.
+   */
+  Ptr (T *ptr, bool ref);
   Ptr (Ptr const&o);
   // allow conversions from T to T const.
   template <typename U>
@@ -187,10 +197,10 @@
 };
 
 template <typename T>
-struct EventMemberImplTraits;
+struct EventMemberImplObjTraits;
 
 template <typename T>
-struct EventMemberImplTraits<Ptr<T> >
+struct EventMemberImplObjTraits<Ptr<T> >
 {
   static T &GetReference (Ptr<T> p) {
     return *PeekPointer (p);
@@ -378,6 +388,16 @@
 }
 
 template <typename T>
+Ptr<T>::Ptr (T *ptr, bool ref) 
+  : m_ptr (ptr)
+{
+  if (ref)
+    {
+      Acquire ();
+    }
+}
+
+template <typename T>
 Ptr<T>::Ptr (Ptr const&o) 
   : m_ptr (PeekPointer (o))
 {
--- a/src/core/random-variable-default-value.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/random-variable-default-value.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -19,9 +19,9 @@
  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
  */
 #include "random-variable-default-value.h"
-#include "ns3/debug.h"
+#include "log.h"
 
-NS_DEBUG_COMPONENT_DEFINE ("RandomVariableDefaultValue");
+NS_LOG_COMPONENT_DEFINE ("RandomVariableDefaultValue");
 
 namespace ns3 {
 
@@ -43,7 +43,8 @@
 RandomVariableDefaultValue::GetCopy (void)
 {
   RandomVariable *variable;
-  bool ok = Parse (m_value, true, &variable);
+  bool ok;
+  ok = Parse (m_value, true, &variable);
   NS_ASSERT (ok);
   return variable;
 }
@@ -74,12 +75,12 @@
       double constant = ReadAsDouble (v, ok);
       if (mustCreate)
 	{
-          NS_DEBUG ("create Constant constant=" << constant);
+          NS_LOG_LOGIC ("create Constant constant=" << constant);
 	  *pVariable = new ConstantVariable (constant);
 	}
       else
         {
-          NS_DEBUG ("parse  Constant constant=" << constant);
+          NS_LOG_LOGIC ("parse  Constant constant=" << constant);
         }
       return ok;
     }
@@ -98,12 +99,12 @@
       maxVal = ReadAsDouble (max, ok);
       if (mustCreate)
 	{
-          NS_DEBUG ("create Uniform min=" << min << ", max=" << max);
+          NS_LOG_LOGIC ("create Uniform min=" << min << ", max=" << max);
 	  *pVariable = new UniformVariable (minVal, maxVal);
 	}
       else
         {
-          NS_DEBUG ("parse  Uniform min=" << min << ", max=" << max);
+          NS_LOG_LOGIC ("parse  Uniform min=" << min << ", max=" << max);
         }
       return ok;
     }
--- a/src/core/random-variable.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/random-variable.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -108,8 +108,8 @@
 {
   if (RandomVariable::globalSeedSet)
     {
-      cout << "Random number generator already initialized!" << endl;
-      cout << "Call to RandomVariable::UseGlobalSeed() ignored" << endl;
+      cerr << "Random number generator already initialized!" << endl;
+      cerr << "Call to RandomVariable::UseGlobalSeed() ignored" << endl;
       return;
     }
   RandomVariable::globalSeed[0] = s0;
@@ -537,7 +537,7 @@
       ValueCDF& current = emp[i];
       if (current.value < prior.value || current.cdf < prior.cdf)
         { // Error
-          cout << "Empirical Dist error,"
+          cerr << "Empirical Dist error,"
                << " current value " << current.value
                << " prior value "   << prior.value
                << " current cdf "   << current.cdf
@@ -684,6 +684,43 @@
   return z;
 }
 
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+// TriangularVariable methods
+TriangularVariable::TriangularVariable() 
+  : m_min(0), m_max(1), m_mode(0.5) { }
+  
+TriangularVariable::TriangularVariable(double s, double l, double mean) 
+  : m_min(s), m_max(l), m_mode(3.0*mean-s-l) { }
+  
+TriangularVariable::TriangularVariable(const TriangularVariable& c) 
+  : RandomVariable(c), m_min(c.m_min), m_max(c.m_max), m_mode(c.m_mode) { }
+
+double TriangularVariable::GetValue()
+{
+  double u = m_generator->RandU01();
+  if(u <= (m_mode - m_min) / (m_max - m_min) )
+    return m_min + sqrt(u * (m_max - m_min) * (m_mode - m_min) );
+  else
+    return m_max - sqrt( (1-u) * (m_max - m_min) * (m_max - m_mode) );
+}
+
+RandomVariable* TriangularVariable::Copy() const
+{
+  return new TriangularVariable(*this);
+}
+
+double TriangularVariable::GetSingleValue(double s, double l, double mean)
+{
+  double mode = 3.0*mean-s-l;
+  double u = m_static_generator->RandU01();
+  if(u <= (mode - s) / (l - s) )
+    return s + sqrt(u * (l - s) * (mode - s) );
+  else
+    return l - sqrt( (1-u) * (l - s) * (l - mode) );
+}
+
+
 }//namespace ns3
 
 
--- a/src/core/random-variable.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/random-variable.h	Fri Sep 28 11:59:46 2007 +0100
@@ -737,6 +737,51 @@
   double m_sigma;
 };
 
+/**
+ * \brief Triangularly Distributed random var
+ * \ingroup randomvariable
+ * 
+ * This distribution is a triangular distribution.  The probablility density
+ * is in the shape of a triangle.
+ */
+class TriangularVariable : public RandomVariable {
+public:
+  /**
+   * Creates a triangle distribution random number generator in the
+   * range [0.0 .. 1.0), with mean of 0.5
+   */
+  TriangularVariable();
+
+  /**
+   * Creates a triangle distribution random number generator with the specified
+   * range
+   * \param s Low end of the range
+   * \param l High end of the range
+   * \param mean mean of the distribution
+   */
+  TriangularVariable(double s, double l, double mean);
+
+  TriangularVariable(const TriangularVariable& c);
+  
+  /**
+   * \return A value from this distribution
+   */
+  virtual double GetValue();
+  virtual RandomVariable*  Copy() const;
+public:
+  /**
+   * \param s Low end of the range
+   * \param l High end of the range
+   * \param mean mean of the distribution
+   * \return A triangularly distributed random number between s and l
+   */
+  static double GetSingleValue(double s, double l, double mean);
+private:
+  double m_min;
+  double m_max;
+  double m_mode;  //easier to work with the mode internally instead of the mean
+                  //they are related by the simple: mean = (min+max+mode)/3
+};
 
 }//namespace ns3
 #endif
--- a/src/core/rng-stream.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/rng-stream.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -269,11 +269,11 @@
     }
     for (i = 3; i < 6; ++i) {
         if (seed[i] >= m2) {
-	  cout << "Seed[" << i << "] = " << seed[i] << endl; 
-            cerr << "*****************************************\n\n"
-                 << "ERROR: Seed[" << i << "] >= 4294944443, Seed is not set."
-                 << "\n\n*****************************************\n\n";
-            return (false);
+	  cerr << "Seed[" << i << "] = " << seed[i] << endl; 
+          cerr << "*****************************************\n\n"
+               << "ERROR: Seed[" << i << "] >= 4294944443, Seed is not set."
+               << "\n\n*****************************************\n\n";
+          return (false);
         }
     }
     if (seed[0] == 0 && seed[1] == 0 && seed[2] == 0) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/stream-tracer-test.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,68 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 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
+ * 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 "stream-tracer.h"
+#include "test.h"
+#include <iostream>
+
+#ifdef RUN_SELF_TESTS
+
+namespace {
+
+class TestStreamTracer : public ns3::Test {
+public:
+  TestStreamTracer ();
+  virtual bool RunTests (void);
+};
+
+static TestStreamTracer gTestStream;
+
+TestStreamTracer::TestStreamTracer ()
+  : Test ("StreamTracer")
+{}
+
+bool
+TestStreamTracer::RunTests (void)
+{
+  bool ok = true;
+  ns3::StreamTracer trace;
+  //trace.setStream (&std::cout);
+  trace << 1;
+  trace << " X ";
+  trace << 1.0;
+  trace << std::endl;
+  trace << "test ";
+  trace << 1 << " test";
+  trace << "test "
+        << 1.0 << " "
+        << 0xdeadbead
+        << std::endl;
+  trace << "0x" << std::hex 
+        << 0xdeadbeaf 
+        << std::dec << " "
+        << 0xdeadbeaf
+        << std::endl;
+  return ok;
+}
+
+
+}; // namespace ns3
+
+#endif /* RUN_SELF_TESTS */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/stream-tracer.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,76 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 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
+ * 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 STREAM_TRACER_H
+#define STREAM_TRACER_H
+
+#include <ostream>
+
+namespace ns3 {
+
+/**
+ * \brief log arbitrary data to std::ostreams
+ * 
+ * Whenever operator << is invoked on this class,
+ * it is forwarded to the stored std::ostream output
+ * stream (if there is one).
+ */
+class StreamTracer {
+public:
+  StreamTracer ()
+      : m_os (0) {}
+  template <typename T>
+  StreamTracer &operator << (T const&v) {
+      if (m_os != 0) 
+        {
+          (*m_os) << v;
+        }
+      return *this;
+  }
+  template <typename T>
+  StreamTracer &operator << (T &v) {
+      if (m_os != 0) 
+        {
+          (*m_os) << v;
+        }
+      return *this;
+  }
+  StreamTracer &operator << (std::ostream &(*v) (std::ostream &)) {
+      if (m_os != 0) 
+        {
+          (*m_os) << v;
+        }
+      return *this;
+  }
+
+  /**
+   * \param os the output stream to store
+   */
+  void SetStream (std::ostream * os) {
+      m_os = os;
+  }
+private:
+  std::ostream *m_os;
+};
+
+}; // namespace ns3
+
+
+#endif /* TRACER_STREAM_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/sv-trace-source.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,246 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 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
+ * 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 SV_TRACE_SOURCE_H
+#define SV_TRACE_SOURCE_H
+
+#include "callback-trace-source.h"
+#include "trace-source.h"
+#include <stdint.h>
+
+namespace ns3 {
+
+class SVTraceSourceBase : public TraceSource {
+public:
+  typedef CallbackTraceSource<int64_t, int64_t> ChangeNotifyCallback;
+
+  SVTraceSourceBase () {}
+  SVTraceSourceBase (SVTraceSourceBase const &o) {}
+  SVTraceSourceBase &operator = (SVTraceSourceBase const &o) {
+      return *this;
+  }
+
+  virtual ~SVTraceSourceBase () {}
+
+  virtual void AddCallback (CallbackBase const & callback, TraceContext const & context) {
+    m_callback.AddCallback (callback, context);
+  }
+  virtual void RemoveCallback (CallbackBase const & callback) {
+    m_callback.RemoveCallback (callback);
+  }
+  virtual void ConnectPrinter (std::ostream &os, const TraceContext &context) {
+    m_callback.ConnectPrinter (os, context);
+  }
+protected:
+  void Notify (int64_t oldVal, int64_t newVal) {
+      if (oldVal != newVal) 
+        {
+          m_callback (oldVal, newVal);
+        }
+  }
+private:
+  ChangeNotifyCallback m_callback;
+};
+
+template <typename T>
+class UVTraceSource;
+
+
+/**
+ * \brief trace variables of type "signed integer"
+ * \ingroup tracing
+ *
+ * This template class implements a POD type: it
+ * behaves like any other variable of type "signed integer"
+ * except that it also reports any changes to its
+ * value with its internal callback.
+ *
+ * To instantiate a 32-bit signed variable (to store
+ * a TCP counter for example), you would create a variable of type
+ * ns3::UVTraceSource<int32_t> :
+ \code
+ #include <stdint.h>
+ #include "sv-trace-source.h"
+
+ ns3::SVTraceSource<uint16_t> var;
+ \endcode
+ * and you would use it like any other variable of type int32_t:
+ \code
+ var += 12;
+ var = 10;
+ var = -10;
+ \endcode
+ */
+template <typename T>
+class SVTraceSource : public SVTraceSourceBase {
+public:
+  SVTraceSource ()
+      : m_var (0)
+  {}
+  SVTraceSource (T const &var) 
+      : m_var (var)
+  {}
+
+  SVTraceSource &operator = (SVTraceSource const &o) {
+      Assign (o.Get ());
+      return *this;
+  }
+  template <typename TT>
+  SVTraceSource &operator = (SVTraceSource<TT> const &o) {
+      Assign (o.Get ());
+      return *this;
+  }
+  template <typename TT>
+  SVTraceSource &operator = (UVTraceSource<TT> const &o) {
+      Assign (o.Get ());
+      return *this;
+  }
+  SVTraceSource &operator++ () {
+      Assign (Get () + 1);
+      return *this;
+  }
+  SVTraceSource &operator-- () {
+      Assign (Get () - 1);
+      return *this;
+  }
+  SVTraceSource operator++ (int) {
+      SVTraceSource old (*this);
+      ++*this;
+      return old;
+  }
+  SVTraceSource operator-- (int) {
+      SVTraceSource old (*this);
+      --*this;
+      return old;
+  }
+  operator T () const {
+      return Get ();
+  }
+
+
+  void Assign (T var) {
+      Notify (m_var, var);
+      m_var = var;
+  }
+  T Get (void) const {
+      return m_var;
+  }
+
+private:
+  T m_var;
+};
+
+template <typename T>
+SVTraceSource<T> &operator += (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
+  lhs.Assign (lhs.Get () + rhs.Get ());
+  return lhs;
+}
+template <typename T>
+SVTraceSource<T> &operator -= (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
+  lhs.Assign (lhs.Get () - rhs.Get ());
+  return lhs;
+}
+template <typename T>
+SVTraceSource<T> &operator *= (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
+  lhs.Assign (lhs.Get () * rhs.Get ());
+  return lhs;
+}
+template <typename T>
+SVTraceSource<T> &operator /= (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
+  lhs.Assign (lhs.Get () / rhs.Get ());
+  return lhs;
+}
+template <typename T>
+SVTraceSource<T> &operator <<= (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
+  lhs.Assign (lhs.Get () << rhs.Get ());
+  return lhs;
+}
+template <typename T>
+SVTraceSource<T> &operator >>= (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
+  lhs.Assign (lhs.Get () >> rhs.Get ());
+  return lhs;
+}
+template <typename T>
+SVTraceSource<T> &operator &= (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
+  lhs.Assign (lhs.Get () & rhs.Get ());
+  return lhs;
+}
+template <typename T>
+SVTraceSource<T> &operator |= (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
+  lhs.Assign (lhs.Get () | rhs.Get ());
+  return lhs;
+}
+template <typename T>
+SVTraceSource<T> &operator ^= (SVTraceSource<T> &lhs, SVTraceSource<T> const &rhs) {
+  lhs.Assign (lhs.Get () ^ rhs.Get ());
+  return lhs;
+}
+
+
+template <typename T, typename U>
+SVTraceSource<T> &operator += (SVTraceSource<T> &lhs, U const &rhs) {
+  lhs.Assign (lhs.Get () + rhs);
+  return lhs;
+}
+template <typename T, typename U>
+SVTraceSource<T> &operator -= (SVTraceSource<T> &lhs, U const &rhs) {
+  lhs.Assign (lhs.Get () - rhs);
+  return lhs;
+}
+template <typename T, typename U>
+SVTraceSource<T> &operator *= (SVTraceSource<T> &lhs, U const &rhs) {
+  lhs.Assign (lhs.Get () * rhs);
+  return lhs;
+}
+template <typename T, typename U>
+SVTraceSource<T> &operator /= (SVTraceSource<T> &lhs, U const &rhs) {
+  lhs.Assign (lhs.Get () / rhs);
+  return lhs;
+}
+template <typename T, typename U>
+SVTraceSource<T> &operator <<= (SVTraceSource<T> &lhs, U const &rhs) {
+  lhs.Assign (lhs.Get () << rhs);
+  return lhs;
+}
+template <typename T, typename U>
+SVTraceSource<T> &operator >>= (SVTraceSource<T> &lhs, U const &rhs) {
+  lhs.Assign (lhs.Get () >> rhs);
+  return lhs;
+}
+template <typename T, typename U>
+SVTraceSource<T> &operator &= (SVTraceSource<T> &lhs, U const &rhs) {
+  lhs.Assign (lhs.Get () & rhs);
+  return lhs;
+}
+template <typename T, typename U>
+SVTraceSource<T> &operator |= (SVTraceSource<T> &lhs, U const &rhs) {
+  lhs.Assign (lhs.Get () | rhs);
+  return lhs;
+}
+template <typename T, typename U>
+SVTraceSource<T> &operator ^= (SVTraceSource<T> &lhs, U const &rhs) {
+  lhs.Assign (lhs.Get () ^ rhs);
+  return lhs;
+}
+
+}; // namespace ns3
+
+#endif /* SV_TRACE_SOURCE_H */
--- a/src/core/test.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/test.h	Fri Sep 28 11:59:46 2007 +0100
@@ -119,6 +119,23 @@
         result = false;                                 \
       }
 /**
+ * Convenience macro to check that a value returned by a test is what
+ * is expected.  Note: this macro assumes a 'bool result = true'
+ * declaration exists in the test function body, and that the function
+ * returns that value.
+ *
+ * \param got value obtained from the test
+ * \param expected value that the test is expected to return
+ */
+#define NS_TEST_ASSERT_UNEQUAL(got, expected)           \
+    if ((got) == (expected))                            \
+      {                                                 \
+        Failure () << __FILE__ << ":" <<__LINE__        \
+                   << ": did not want " << (expected)   \
+                   << ", got " << (got) << std::endl;   \
+        result = false;                                 \
+      }
+/**
  * Convenience macro to check an assertion is held during an unit
  * test.  Note: this macro assumes a 'bool result = true' declaration
  * exists in the test function body, and that the function returns
@@ -130,8 +147,8 @@
     if (!(assertion))                                   \
       {                                                 \
         Failure () << __FILE__ << ":" <<__LINE__        \
-                   << ": assertion `" << (assertion)    \
-                   << "'failed." << std::endl;          \
+                   << ": assertion `" << #assertion     \
+                   << "' failed." << std::endl;         \
         result = false;                                 \
       }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/trace-context-element.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,41 @@
+#include "trace-context-element.h"
+
+namespace ns3 {
+
+std::string 
+ElementRegistry::GetTypeName (uint16_t uid)
+{
+  InfoVector *vec = GetInfoVector ();
+  struct Info info = (*vec)[uid - 1];
+  return info.getTypeName ();
+}
+uint32_t 
+ElementRegistry::GetSize (uint16_t uid)
+{
+  InfoVector *vec = GetInfoVector ();
+  struct Info info = (*vec)[uid - 1];
+  return info.size;
+}
+void 
+ElementRegistry::Print (uint16_t uid, uint8_t *instance, std::ostream &os)
+{
+  InfoVector *vec = GetInfoVector ();
+  struct Info info = (*vec)[uid - 1];
+  info.print (instance, os);
+}
+void 
+ElementRegistry::Destroy (uint16_t uid, uint8_t *instance)
+{
+  InfoVector *vec = GetInfoVector ();
+  struct Info info = (*vec)[uid - 1];
+  info.destroy (instance);
+}
+ElementRegistry::InfoVector *
+ElementRegistry::GetInfoVector (void)
+{
+  static InfoVector vector;
+  return &vector;
+}
+
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/trace-context-element.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,211 @@
+#ifndef TRACE_CONTEXT_ELEMENT_H
+#define TRACE_CONTEXT_ELEMENT_H
+
+#include <string>
+#include <vector>
+
+#define NS_TRACE_CONTEXT_ELEMENT_ENSURE_REGISTERED(x)          \
+namespace {						       \
+static class thisisaveryverylongclassname ##x		       \
+  {							       \
+  public:						       \
+    thisisaveryverylongclassname ##x ()			       \
+      { uint32_t uid; uid = x::GetUid ();}		       \
+  } g_thisisanotherveryveryverylongname ##x ;		       \
+}
+
+namespace ns3 {
+
+/**
+ * \brief an item stored in a TraceContext
+ *
+ * To store trace context information in a TraceContext instance,
+ * users must subclass this base class and store subclass instances
+ * in a TraceContext with TraceContext::Add.
+ *
+ * Each subclass should define and implement:
+ *   - a public default constructor: it is used by the internals
+ *     of the implementation of TraceContext.
+ *   - a public destructor: it is also used by the internals of
+ *     the implementation of TraceContext.
+ *   - a public static method named GetUid which returns a 16 bit 
+ *     integer. The integer returned from this method should be
+ *     allocated with the protected AllocatedUid method.
+ *   - a public Print method: this method is used by the 
+ *     TraceContext::Print method to print the content of each
+ *     of the trace context element stored in the trace context.
+ *     This method takes a c++ output stream and argument and is
+ *     expected to write an ascii string describing its content
+ *     in this output stream.
+ *   - a public GetTypeName method which returns the fully-qualified
+ *     c++ type name of this subclass as a string.
+ *
+ * A typical subclass should look like this:
+ * \code
+ * class MyContext : public TraceContextElement
+ * {
+ * public:
+ *   // the _required_ public API
+ *   static uint16_t GetUid (void);
+ *   MyContext ();
+ *   ~MyContext ();
+ *   void Print (std::ostream &os) const;
+ *   std::string GetTypeName (void) const;
+ *
+ *   // the user-specific API to manipulate the context.
+ *   void SetData (uint8_t data);
+ *   uint8_t GetData (void) const;
+ * private:
+ *   uint8_t m_myContextData;
+ * };
+ *
+ * uint16_t 
+ * MyContext::GetUid (void)
+ * {
+ *   static uint16_t uid = AllocateUid<MyContext> ("MyContext");
+ *   return uid;
+ * }
+ * MyContext::MyContext ()
+ * {}
+ * MyContext::~MyContext ()
+ * {}
+ * void 
+ * MyContext::Print (std::ostream &os) const
+ * {
+ *   os << "mycontext=" << (uint32_t) m_myContextData;
+ * }
+ * std::string 
+ * MyContext::GetTypeName (void) const
+ * {
+ *   // return a fully-qualified c++ type name
+ *   return "MyContext";
+ * }
+ * void 
+ * MyContext::SetData (uint8_t data)
+ * {
+ *   m_myContextData = data;
+ * }
+ * uint8_t 
+ * MyContext::GetData (void) const
+ * {
+ *   return m_myContextData;
+ * }
+ * \endcode
+ */
+class TraceContextElement
+{
+protected:
+  /**
+   * \param name a string which uniquely identifies the type
+   *        of the subclass which is calling this method.
+   * \returns a unique 32 bit integer associated to the
+   *          input string.
+   *
+   * Subclasses are expected to call this method from their
+   * public static GetUid method.
+   */
+  template <typename T>
+  static uint16_t AllocateUid (std::string name);
+};
+
+} // namespace ns3
+
+namespace ns3 {
+
+/**
+ * \brief a registry of TraceContextElement subclasses
+ * \internal
+ */
+class ElementRegistry
+{
+public:
+  template <typename T>
+  static uint16_t AllocateUid (std::string name);
+
+  static uint32_t GetSize (uint16_t uid);
+  static void Print (uint16_t uid, uint8_t *instance, std::ostream &os);
+  static std::string GetTypeName (uint16_t uid);
+  static void Destroy (uint16_t uid, uint8_t *instance);
+private:
+  typedef std::string (*GetTypeNameCb) (void);
+  typedef void (*PrintCb) (uint8_t *instance, std::ostream &os);
+  typedef void (*DestroyCb) (uint8_t *instance);
+  struct Info {
+    uint32_t size;
+    std::string uidString;
+    GetTypeNameCb getTypeName;
+    PrintCb print;
+    DestroyCb destroy;
+  };
+  typedef std::vector<struct Info> InfoVector;
+  static InfoVector *GetInfoVector (void);
+  template <typename T>
+  static std::string DoGetTypeName (void);
+  template <typename T>
+  static void DoPrint (uint8_t *instance, std::ostream &os);
+  template <typename T>
+  static void DoDestroy (uint8_t *instance);  
+};
+
+template <typename T>
+void 
+ElementRegistry::DoPrint (uint8_t *instance, std::ostream &os)
+{
+  static T obj;
+  // make sure we are aligned.
+  memcpy ((void*)&obj, instance, sizeof (T));
+  obj.Print (os);
+}
+template <typename T>
+std::string
+ElementRegistry::DoGetTypeName (void)
+{
+  static T obj;
+  return obj.GetTypeName ();
+}
+template <typename T>
+void 
+ElementRegistry::DoDestroy (uint8_t *instance)
+{
+  static T obj;
+  // make sure we are aligned.
+  memcpy ((void*)&obj, instance, sizeof (T));
+  obj.~T ();
+}
+
+template <typename T>
+uint16_t 
+ElementRegistry::AllocateUid (std::string name)
+{
+  InfoVector *vec = GetInfoVector ();
+  uint16_t uid = 1;
+  for (InfoVector::iterator i = vec->begin (); i != vec->end (); i++)
+    {
+      if (i->uidString == name)
+	{
+	  return uid;
+	}
+      uid++;
+    }
+  struct Info info;
+  info.size = sizeof (T);
+  info.uidString = name;
+  info.getTypeName = &ElementRegistry::DoGetTypeName<T>;
+  info.print = &ElementRegistry::DoPrint<T>;
+  info.destroy = &ElementRegistry::DoDestroy<T>;
+  vec->push_back (info);
+  return vec->size ();
+}
+
+
+
+template <typename T>
+uint16_t 
+TraceContextElement::AllocateUid (std::string name)
+{
+  return ElementRegistry::AllocateUid<T> (name);
+}
+
+} // namespace ns3
+
+#endif /* TRACE_CONTEXT_ELEMENT_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/trace-context.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,459 @@
+/* -*- 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
+ * 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 "trace-context.h"
+#include "trace-context-element.h"
+#include "assert.h"
+
+namespace ns3 {
+
+TraceContext::Iterator::Iterator ()
+  : m_buffer (0),
+    m_size (0),
+    m_current (0)
+{}
+TraceContext::Iterator::Iterator (uint8_t *buffer, uint16_t size)
+  : m_buffer (buffer),
+    m_size (size),
+    m_current (0)
+{
+  m_uid = m_buffer[m_current];
+}
+bool
+TraceContext::Iterator::IsLast (void) const
+{
+  if (m_buffer == 0 || m_uid == 0 || m_current >= m_size)
+    {
+      return true;
+    }
+  return false;
+}
+void
+TraceContext::Iterator::Next (void)
+{
+  if (m_buffer == 0)
+    {
+      return;
+    }
+  if (m_uid == 0)
+    {
+      return;
+    }
+  else
+    {
+      uint8_t size = ElementRegistry::GetSize (m_uid); 
+      m_current += 1 + size;
+    }
+  m_uid = m_buffer[m_current];
+}
+std::string
+TraceContext::Iterator::Get (void) const
+{
+  std::string name = ElementRegistry::GetTypeName (m_uid);
+  return name;
+}
+
+TraceContext::TraceContext ()
+  : m_data (0)
+{}
+TraceContext::TraceContext (TraceContext const &o)
+  : m_data (o.m_data)
+{
+  if (m_data != 0)
+    {
+      m_data->count++;
+    }
+}
+TraceContext const & 
+TraceContext::operator = (TraceContext const &o)
+{
+  if (m_data != 0)
+    {
+      m_data->count--;
+      if (m_data->count == 0)
+        {
+          uint8_t *buffer = (uint8_t *)m_data;
+          delete [] buffer;
+        }
+    }
+  m_data = o.m_data;
+  if (m_data != 0)
+    {
+      m_data->count++;
+    }
+  return *this;
+}
+TraceContext::~TraceContext ()
+{
+  if (m_data != 0)
+    {
+      m_data->count--;
+      if (m_data->count == 0)
+        {
+          uint8_t *buffer = (uint8_t *)m_data;
+          delete [] buffer;
+        }
+    }
+}
+
+void 
+TraceContext::Union (TraceContext const &o)
+{
+  if (o.m_data == 0)
+    {
+      return;
+    }
+  uint16_t currentUid;
+  uint16_t i = 0;
+  while (i < o.m_data->size) 
+    {
+      currentUid = o.m_data->data[i];
+      uint8_t size = ElementRegistry::GetSize (currentUid);
+      uint8_t *selfBuffer = CheckPresent (currentUid);
+      uint8_t *otherBuffer = &(o.m_data->data[i+1]);
+      if (selfBuffer != 0)
+        {
+          if (memcmp (selfBuffer, otherBuffer, size) != 0)
+            {
+              NS_FATAL_ERROR ("You cannot add TraceContexts which "<<
+                              "have different values stored in them.");
+            }
+        }
+      else
+        {
+          DoAdd (currentUid, otherBuffer);
+        }
+      i += 1 + size;
+    }
+}
+
+uint8_t *
+TraceContext::CheckPresent (uint8_t uid) const
+{
+  if (m_data == 0)
+    {
+      return false;
+    }
+  uint8_t currentUid;
+  uint16_t i = 0;
+  do {
+    currentUid = m_data->data[i];
+    uint8_t size = ElementRegistry::GetSize (currentUid);
+    if (currentUid == uid)
+      {
+        return &m_data->data[i+1];
+      }
+    i += 1 + size;
+  } while (i < m_data->size && currentUid != 0);
+  return 0;
+}
+
+
+bool
+TraceContext::DoAdd (uint8_t uid, uint8_t const *buffer)
+{
+  NS_ASSERT (uid != 0);
+  uint8_t size = ElementRegistry::GetSize (uid);
+  uint8_t *present = CheckPresent (uid);
+  if (present != 0) {
+    if (memcmp (present, buffer, size) == 0)
+      {
+        return true;
+      }
+    else
+      {
+        return false;
+      }
+  }
+  if (m_data == 0)
+    {
+      uint16_t newSize = 1 + size;
+      uint16_t allocatedSize;
+      if (newSize > 4)
+        {
+          allocatedSize = sizeof (struct Data) + newSize - 4;
+        }
+      else
+        {
+          allocatedSize = sizeof (struct Data);
+        }
+      struct Data *data = (struct Data *) (new uint8_t [allocatedSize] ());
+      data->size = newSize;
+      data->count = 1;
+      data->data[0] = uid;
+      memcpy (data->data + 1, buffer, size);
+      m_data = data;
+    }
+  else
+    {
+      uint16_t newSize = m_data->size + 1 + size;
+      uint16_t allocatedSize;
+      if (newSize > 4)
+        {
+          allocatedSize = sizeof (struct Data) + newSize - 4;
+        }
+      else
+        {
+          allocatedSize = sizeof (struct Data);
+        }
+      struct Data *data = (struct Data *) (new uint8_t [allocatedSize] ());
+      data->size = newSize;
+      data->count = 1;
+      memcpy (data->data, m_data->data, m_data->size);
+      data->data[m_data->size] = uid;
+      memcpy (data->data + m_data->size + 1, buffer, size);
+      m_data->count--;
+      if (m_data->count == 0)
+        {
+          uint8_t *buffer = (uint8_t *)m_data;
+          delete [] buffer;
+        }
+      m_data = data;
+    }
+  return true;
+}
+bool
+TraceContext::DoGet (uint8_t uid, uint8_t *buffer) const
+{
+  if (m_data == 0)
+    {
+      return false;
+    }
+  uint8_t currentUid;
+  uint16_t i = 0;
+  do {
+    currentUid = m_data->data[i];
+    uint8_t size = ElementRegistry::GetSize (currentUid);
+    if (currentUid == uid)
+      {
+        memcpy (buffer, &m_data->data[i+1], size);
+        return true;
+      }
+    i += 1 + size;
+  } while (i < m_data->size && currentUid != 0);
+  return false;
+}
+
+void 
+TraceContext::Print (std::ostream &os) const
+{
+  if (m_data == 0)
+    {
+      return;
+    }
+  uint8_t currentUid;
+  uint16_t i = 0;
+  do {
+    currentUid = m_data->data[i];
+    uint8_t size = ElementRegistry::GetSize (currentUid);
+    uint8_t *instance = &m_data->data[i+1];
+    ElementRegistry::Print (currentUid, instance, os);
+    i += 1 + size;
+    if (i < m_data->size && currentUid != 0)
+      {
+        os << " ";
+      }
+    else
+      {
+        break;
+      }
+  } while (true);
+}
+TraceContext::Iterator 
+TraceContext::Begin (void) const
+{
+  if (m_data == 0)
+    {
+      return Iterator ();
+    }
+  return Iterator (m_data->data, m_data->size);
+}
+
+void 
+TraceContext::PrintAvailable (std::ostream &os, std::string separator) const
+{
+  if (m_data == 0)
+    {
+      return;
+    }
+  uint8_t currentUid;
+  uint16_t i = 0;
+  do {
+    currentUid = m_data->data[i];
+    uint8_t size = ElementRegistry::GetSize (currentUid);
+    os << ElementRegistry::GetTypeName (currentUid);
+    i += 1 + size;
+    if (i < m_data->size && currentUid != 0)
+      {
+        os << separator;
+      }
+    else
+      {
+        break;
+      }
+  } while (true);
+}
+
+bool 
+TraceContext::IsSimilar (const TraceContext &o) const
+{
+  if (m_data == 0 && o.m_data == 0)
+    {
+      return true;
+    }
+  if ((m_data != 0 && o.m_data == 0) || 
+      (m_data == 0 && o.m_data != 0))
+    {
+      return false;
+    }
+  uint8_t myCurrentUid;
+  uint16_t myI = 0;
+  uint8_t otherCurrentUid;
+  uint16_t otherI = 0;
+
+  myCurrentUid = m_data->data[myI];
+  otherCurrentUid = o.m_data->data[otherI];
+
+  while (myCurrentUid == otherCurrentUid && 
+         myCurrentUid != 0 && 
+         otherCurrentUid != 0 &&
+         myI < m_data->size &&
+         otherI < o.m_data->size)
+    {
+      uint8_t mySize = ElementRegistry::GetSize (myCurrentUid);
+      uint8_t otherSize = ElementRegistry::GetSize (otherCurrentUid);
+      myI += 1 + mySize;
+      otherI += 1 + otherSize;
+      myCurrentUid = m_data->data[myI];
+      otherCurrentUid = o.m_data->data[otherI];
+    }
+  if (myCurrentUid == 0 && otherCurrentUid == 0)
+    {
+      return true;
+    }
+  else
+    {
+      return false;
+    }
+}
+
+std::ostream& operator<< (std::ostream& os, const TraceContext &context)
+{
+  context.Print (os);
+  return os;
+}
+
+}//namespace ns3
+
+#include "test.h"
+#include <sstream>
+
+namespace ns3 {
+
+template <int N>
+class Ctx : public TraceContextElement
+{
+public:
+  static uint16_t GetUid (void) {static uint16_t uid = AllocateUid<Ctx<N> > (GetTypeName ()); return uid;}
+  static std::string GetTypeName (void) {std::ostringstream oss; oss << "Ctx" << N; return oss.str ();}
+  Ctx () : m_v (0) {}
+  Ctx (int v) : m_v (v) {}
+  void Print (std::ostream &os) {os << N;}
+  int Get (void) const { return N;}
+private:
+  int m_v;
+};
+
+class TraceContextTest : public Test
+{
+public:
+  TraceContextTest ();
+  virtual bool RunTests (void);
+};
+
+TraceContextTest::TraceContextTest ()
+  : Test ("TraceContext")
+{}
+bool 
+TraceContextTest::RunTests (void)
+{
+  bool ok = true;
+
+  TraceContext ctx;
+  Ctx<0> v0;
+  Ctx<0> v01 = Ctx<0> (1);
+  Ctx<1> v1;
+  Ctx<2> v2;
+  Ctx<3> v3;
+
+  if (ctx.SafeGet (v0))
+    {
+      ok = false;
+    }
+  ctx.AddElement (v0);
+  ctx.AddElement (v0);
+  if (ctx.SafeAdd (v01))
+    {
+      ok = false;
+    }
+  ctx.GetElement (v0);
+  ctx.AddElement (v1);
+  ctx.GetElement (v1);
+  ctx.GetElement (v0);
+  ctx.GetElement (v1);
+
+  TraceContext copy = ctx;
+  ctx.GetElement (v0);
+  ctx.GetElement (v1);
+  copy.GetElement (v0);
+  copy.GetElement (v1);
+  copy.AddElement (v2);
+  copy.GetElement (v0);
+  copy.GetElement (v1);
+  copy.GetElement (v2);
+  ctx.AddElement (v3);
+  ctx.GetElement (v0);
+  ctx.GetElement (v1);
+  ctx.GetElement (v3);
+
+  if (ctx.SafeGet (v2))
+    {
+      ok = false;
+    }
+  if (copy.SafeGet (v3))
+    {
+      ok = false;
+    }
+  ctx.Union (copy);
+  ctx.GetElement (v2);
+  if (copy.SafeGet (v3))
+    {
+      ok = false;
+    }
+  copy.Union (ctx);
+  copy.GetElement (v3);  
+  
+  return ok;
+}
+
+static TraceContextTest g_traceContextTest;
+
+
+}//namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/trace-context.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,204 @@
+/* -*- 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
+ * 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 TRACE_CONTEXT_H
+#define TRACE_CONTEXT_H
+
+#include <stdint.h>
+#include <vector>
+#include "fatal-error.h"
+#include "trace-context-element.h"
+
+namespace ns3 {
+
+/**
+ * \brief Provide context to trace sources
+ * \ingroup tracing
+ *
+ * Instances of this class are used to hold context
+ * for each trace source. Each instance holds a list of
+ * TraceContextElement. Trace sinks can lookup these contexts
+ * from this list with the ns3::TraceContext::Get method.
+ * They can also ask the TraceContext for the list of 
+ * TraceContextElements it contains with the PrintAvailable method.
+ *
+ * This class is implemented
+ * using Copy On Write which means that copying unmodified
+ * versions of this class is very cheap. However, modifying
+ * the content of this class through a call 
+ * to ns3::TraceContext::AddElement or ns3::TraceContext::Union 
+ * will trigger a costly memory reallocation if needed.
+ */
+class TraceContext
+{
+public:
+  TraceContext ();
+  TraceContext (TraceContext const &o);
+  TraceContext const & operator = (TraceContext const &o);
+  ~TraceContext ();
+
+  /**
+   * \param context add context to list of trace contexts.
+   *
+   * A copy of the input context is appended at the end of the list
+   * stored in this TraceContext.
+   */
+  template <typename T>
+  void AddElement (T const &context);
+
+  /**
+   * \param o the other context
+   *
+   * Perform the Union operation (in the sense of set theory) on the
+   * two input lists of elements. This method is used in the
+   * ns3::CallbackTraceSource class when multiple sinks are connected
+   * to a single source to ensure that the source does not need
+   * to store a single TraceContext instance per connected sink.
+   * Instead, all sinks share the same TraceContext.
+   */
+  void Union (TraceContext const &o);
+
+  /**
+   * \param context context to get from this list of trace contexts.
+   * \returns true if the requested trace context element was found 
+   *          in this TraceContext, false otherwise.
+   */
+  template <typename T>
+  bool GetElement (T &context) const;
+
+  /**
+   * \param os a c++ STL output stream
+   *
+   * Iterate over the list of TraceContextElement stored in this
+   * TraceContext and invoke each of their Print method.
+   */
+  void Print (std::ostream &os) const;
+  /**
+   * \param os a c++ STL output stream
+   * \param separator the separator inserted between each TraceContextElement typename.
+   *
+   * Print the typename of each TraceContextElement stored in this TraceContext.
+   */
+  void PrintAvailable (std::ostream &os, std::string separator) const;
+  class Iterator 
+  {
+  public:
+    void Next (void);
+    bool IsLast (void) const;
+    std::string Get (void) const;
+  private:
+    friend class TraceContext;
+    Iterator ();
+    Iterator (uint8_t *buffer, uint16_t index);
+    uint8_t *m_buffer;
+    uint16_t m_size;
+    uint16_t m_current;
+    uint8_t m_uid;
+  };
+  Iterator Begin (void) const;
+  /**
+   * \param o another trace context
+   * \returns true if the input trace context contains exactly the same set of
+   *          TraceContextElement instances, false otherwise.
+   *
+   * This method does not test for equality: the content of each matching 
+   * TraceContextElement could be different. It merely checks that both
+   * trace contexts contain the same types of TraceContextElements.
+   */
+  bool IsSimilar (const TraceContext &o) const;
+private:
+  friend class TraceContextTest;
+  // used exclusively for testing code.
+  template <typename T>
+  bool SafeGet (T &context) const;
+  template <typename T>
+  bool SafeAdd (const T &context);
+
+  uint8_t *CheckPresent (uint8_t uid) const;
+  bool DoAdd (uint8_t uid, uint8_t const *buffer);
+  bool DoGet (uint8_t uid, uint8_t *buffer) const;
+
+  struct Data {
+    uint16_t count;
+    uint16_t size;
+    uint8_t data[4];
+  } * m_data;
+};
+
+std::ostream& operator<< (std::ostream& os, const TraceContext &context);
+
+}//namespace ns3
+
+namespace ns3 {
+
+template <typename T>
+void 
+TraceContext::AddElement (T const &context)
+{
+  const TraceContextElement *parent;
+  // if the following assignment fails, it is because the input
+  // to this function is not a subclass of the TraceContextElement class.
+  parent = &context;
+  uint8_t *data = (uint8_t *) &context;
+  bool ok = DoAdd (T::GetUid (), data);
+  if (!ok)
+    {
+      NS_FATAL_ERROR ("Trying to add twice the same type with different values is invalid.");
+    }
+}
+template <typename T>
+bool
+TraceContext::GetElement (T &context) const
+{
+  TraceContextElement *parent;
+  // if the following assignment fails, it is because the input
+  // to this function is not a subclass of the TraceContextElement class.
+  parent = &context;
+  uint8_t *data = (uint8_t *) &context;
+  bool found = DoGet (T::GetUid (), data);
+  return found;
+}
+template <typename T>
+bool
+TraceContext::SafeGet (T &context) const
+{
+  TraceContextElement *parent;
+  // if the following assignment fails, it is because the input
+  // to this function is not a subclass of the TraceContextElement class.
+  parent = &context;
+  uint8_t *data = (uint8_t *) &context;
+  bool found = DoGet (T::GetUid (), data);
+  return found;
+}
+template <typename T>
+bool
+TraceContext::SafeAdd (const T &context)
+{
+  const TraceContextElement *parent;
+  // if the following assignment fails, it is because the input
+  // to this function is not a subclass of the TraceContextElement class.
+  parent = &context;
+  uint8_t *data = (uint8_t *) &context;
+  bool ok = DoAdd (T::GetUid (), data);
+  return ok;
+}
+}//namespace ns3
+
+#endif /* TRACE_CONTEXT_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/trace-doc.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,74 @@
+#include "trace-doc.h"
+
+namespace ns3 {
+
+TraceDoc::TraceDoc ()
+  : m_help ("empty help")
+{}
+
+TraceDoc::TraceDoc (std::string help)
+  : m_help (help)
+{}
+TraceDoc::TraceDoc (std::string help,
+		    std::string arg0Type,
+		    std::string arg0Help)
+  : m_help (help)
+{
+  m_argVector.push_back (std::make_pair (arg0Type, arg0Help));
+}
+TraceDoc::TraceDoc (std::string help,
+		    std::string arg0Type,
+		    std::string arg0Help,
+		    std::string arg1Type,
+		    std::string arg1Help)
+  : m_help (help)
+{
+  m_argVector.push_back (std::make_pair (arg0Type, arg0Help));
+  m_argVector.push_back (std::make_pair (arg1Type, arg1Help));
+}
+TraceDoc::TraceDoc (std::string help,
+		    std::string arg0Type,
+		    std::string arg0Help,
+		    std::string arg1Type,
+		    std::string arg1Help,
+		    std::string arg2Type,
+		    std::string arg2Help)
+  : m_help (help)
+{
+  m_argVector.push_back (std::make_pair (arg0Type, arg0Help));
+  m_argVector.push_back (std::make_pair (arg1Type, arg1Help));
+  m_argVector.push_back (std::make_pair (arg2Type, arg2Help));
+}
+TraceDoc::TraceDoc (std::string help,
+		    std::string arg0Type,
+		    std::string arg0Help,
+		    std::string arg1Type,
+		    std::string arg1Help,
+		    std::string arg2Type,
+		    std::string arg2Help,
+		    std::string arg3Type,
+		    std::string arg3Help)
+  : m_help (help)
+{
+  m_argVector.push_back (std::make_pair (arg0Type, arg0Help));
+  m_argVector.push_back (std::make_pair (arg1Type, arg1Help));
+  m_argVector.push_back (std::make_pair (arg2Type, arg2Help));
+  m_argVector.push_back (std::make_pair (arg3Type, arg3Help));
+}
+std::string 
+TraceDoc::GetHelp (void) const
+{
+  return m_help;
+}
+TraceDoc::Iterator 
+TraceDoc::ArgsBegin (void) const
+{
+  return m_argVector.begin ();
+}
+TraceDoc::Iterator 
+TraceDoc::ArgsEnd (void) const
+{
+  return m_argVector.end ();
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/trace-doc.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,103 @@
+#ifndef TRACE_DOC_H
+#define TRACE_DOC_H
+
+#include <vector>
+#include <string>
+
+namespace ns3 {
+
+/**
+ * \brief describe the signature of a trace source
+ */
+class TraceDoc
+{
+  typedef std::vector<std::pair<std::string,std::string> > ArgVector;
+public:
+  typedef ArgVector::const_iterator Iterator;
+  TraceDoc ();
+  /**
+   * \param help a description of the purpose of the trace source
+   */
+  TraceDoc (std::string help);
+  /**
+   * \param help a description of the purpose of the trace source
+   * \param arg1Type the fully-qualified typename of the first argument of the trace source
+   * \param arg1Help the purpose of the first argument of the trace source
+   */
+  TraceDoc (std::string help,
+	    std::string arg1Type,
+	    std::string arg1Help);
+  /**
+   * \param help a description of the purpose of the trace source
+   * \param arg1Type the fully-qualified typename of the first argument of the trace source
+   * \param arg1Help the purpose of the first argument of the trace source
+   * \param arg2Type the fully-qualified typename of the second argument of the trace source
+   * \param arg2Help the purpose of the second argument of the trace source
+   */
+  TraceDoc (std::string help,
+	    std::string arg1Type,
+	    std::string arg1Help,
+	    std::string arg2Type,
+	    std::string arg2Help);
+  /**
+   * \param help a description of the purpose of the trace source
+   * \param arg1Type the fully-qualified typename of the first argument of the trace source
+   * \param arg1Help the purpose of the first argument of the trace source
+   * \param arg2Type the fully-qualified typename of the second argument of the trace source
+   * \param arg2Help the purpose of the second argument of the trace source
+   * \param arg3Type the fully-qualified typename of the third argument of the trace source
+   * \param arg3Help the purpose of the third argument of the trace source
+   */
+  TraceDoc (std::string help,
+	    std::string arg1Type,
+	    std::string arg1Help,
+	    std::string arg2Type,
+	    std::string arg2Help,
+	    std::string arg3Type,
+	    std::string arg3Help);
+  /**
+   * \param help a description of the purpose of the trace source
+   * \param arg1Type the fully-qualified typename of the first argument of the trace source
+   * \param arg1Help the purpose of the first argument of the trace source
+   * \param arg2Type the fully-qualified typename of the second argument of the trace source
+   * \param arg2Help the purpose of the second argument of the trace source
+   * \param arg3Type the fully-qualified typename of the third argument of the trace source
+   * \param arg3Help the purpose of the third argument of the trace source
+   * \param arg4Type the fully-qualified typename of the fourth argument of the trace source
+   * \param arg4Help the purpose of the fourth argument of the trace source
+   */
+  TraceDoc (std::string help,
+	    std::string arg1Type,
+	    std::string arg1Help,
+	    std::string arg2Type,
+	    std::string arg2Help,
+	    std::string arg3Type,
+	    std::string arg3Help,
+	    std::string arg4Type,
+	    std::string arg4Help);
+  /**
+   * \returns the help string associated to this trace source
+   */
+  std::string GetHelp (void) const;
+  /**
+   * \returns an iterator which points to the first descriptor of the trace source.
+   *
+   * Each descriptor is a pair of strings. The first one describes the type of the argument
+   * while the second one describeds the purpose of the argument.
+   */
+  Iterator ArgsBegin (void) const;
+  /**
+   * \returns an iterator which points to the last descriptor of the trace source.
+   *
+   * Each descriptor is a pair of strings. The first one describes the type of the argument
+   * while the second one describeds the purpose of the argument.
+   */
+  Iterator ArgsEnd (void) const;
+private:
+  ArgVector m_argVector;
+  std::string m_help;
+};
+
+} // namespace ns3
+
+#endif /* TRACE_DOC_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/trace-resolver.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,107 @@
+/* -*- 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
+ * 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 "trace-resolver.h"
+#include "log.h"
+
+NS_LOG_COMPONENT_DEFINE ("TraceResolver");
+
+namespace ns3 {
+
+TraceResolver::TraceResolver ()
+  : m_count (1)
+{}
+
+TraceResolver::~TraceResolver ()
+{}
+
+void 
+TraceResolver::Ref (void)
+{
+  m_count++;
+}
+void 
+TraceResolver::Unref (void)
+{
+  m_count--;
+  if (m_count == 0)
+    {
+      NS_LOG_LOGIC ("delete "<<this);
+      delete this;
+    }
+}
+
+std::string 
+TraceResolver::GetElement (std::string path)
+{
+  std::string::size_type cur = 1;
+  // check that first char is "/"
+  std::string::size_type next = path.find ("/", cur);
+  std::string id = std::string (path, cur, next-1);
+  return id;
+}
+std::string 
+TraceResolver::GetSubpath (std::string path)
+{
+  std::string::size_type cur = 1;
+  // check that first char is "/"
+  std::string::size_type next = path.find ("/", cur);
+  std::string subpath;
+  if (next != std::string::npos)
+    {
+      subpath = std::string (path, next, std::string::npos);
+    }
+  else
+    {
+      subpath = "";
+    }
+  return subpath;
+}
+
+void 
+TraceResolver::SourceCollection::AddUnique (std::string path, 
+                                            const TraceContext &context,
+                                            const TraceDoc &doc)
+{
+  for (SourceVector::const_iterator i = m_sources.begin (); i != m_sources.end (); i++)
+    {
+      if (i->path == path &&
+          context.IsSimilar (i->context))
+        {
+          return;
+        }
+    }
+  struct Source source;
+  source.path = path;
+  source.context = context;
+  source.doc = doc;
+  m_sources.push_back (source);
+}
+TraceResolver::SourceCollection::Iterator
+TraceResolver::SourceCollection::Begin (void) const
+{
+  return m_sources.begin ();
+}
+TraceResolver::SourceCollection::Iterator
+TraceResolver::SourceCollection::End (void) const
+{
+  return m_sources.end ();
+}
+}//namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/trace-resolver.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,159 @@
+/* -*- 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
+ * 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 TRACE_RESOLVER_H
+#define TRACE_RESOLVER_H
+
+#include <string>
+#include <list>
+#include "trace-context.h"
+#include "trace-doc.h"
+
+namespace ns3 {
+
+class CallbackBase;
+
+/**
+ * \brief the base class which is used to recursively perform trace
+ *        namespace resolution.
+ * \ingroup tracing
+ *
+ * Although users could conceivably implement their own trace resolver
+ * subclasses, doing so is complicated so, it is recommended to use
+ * the default implementation ns3::CompositeTraceResolver instead.
+ */
+class TraceResolver
+{
+public:
+
+  TraceResolver ();
+  virtual ~TraceResolver ();
+  void Ref (void);
+  void Unref (void);
+
+  /**
+   * \param path the namespace path to resolver
+   * \param cb the callback to connect to the matching namespace
+   * \param context the context in which to store the trace context
+   *
+   * First, extract the leading path element from the input path, and 
+   * match this leading patch element against any terminal trace source
+   * contained in this trace resolver.
+   * Second, recursively resolve the rest of the path using other 
+   * objects if there are any.
+   * If there is any TraceContextElement associated to one of the matching
+   * elements, it should be added to the input TraceContext.
+   */
+  virtual void Connect (std::string path, CallbackBase const &cb, const TraceContext &context) = 0;
+  /**
+   * \param path the namespace path to resolver
+   * \param cb the callback to disconnect in the matching namespace
+   *
+   * This method should behave as Connect.
+   */
+  virtual void Disconnect (std::string path, CallbackBase const &cb) = 0;
+
+  /**
+   * \brief hold a list of trace sources
+   */
+  class SourceCollection
+  {
+  public:
+    /**
+     * \brief describe a single trace source
+     */
+    struct Source
+    {
+      /**
+       * The trace path associated to this trace source
+       */
+      std::string path;
+      /**
+       * The trace context associated to this trace source
+       */
+      TraceContext context;
+      /**
+       * Document the signature of this trace source
+       */
+      TraceDoc doc;
+    };
+    typedef std::vector<struct Source>::const_iterator Iterator;
+    void AddUnique (std::string path, 
+                    const TraceContext &context,
+                    const TraceDoc &doc);
+
+    /**
+     * \returns an iterator which points to the first element of the set of
+     *          trace sources collected in this SourceCollection object.
+     */
+    Iterator Begin (void) const;
+    /**
+     * \returns an iterator which points to the last element of the set of
+     *          trace sources collected in this SourceCollection object.
+     */
+    Iterator End (void) const;
+  private:
+    typedef std::vector<struct Source> SourceVector;
+    SourceVector m_sources;
+  };
+  /**
+   * \param path the path to the current recursive level.
+   * \param context the trace context associated to the current recursive level
+   * \param collection the collection in which to gather every trace source found.
+   *
+   * This method is invoked recursively until all trace sources have been
+   * stored in the output SourceCollection argument.
+   */
+  virtual void CollectSources (std::string path, const TraceContext &context, 
+                               SourceCollection *collection) = 0;
+
+  /**
+   * \param os the output stream to which ascii output should be written.
+   * \param context the context associated to the current recursive level.
+   *
+   * This method is invoked recursively until each trace source has been
+   * connected to a trace sink which can output an ascii representation
+   * of each trace event on the output stream specified.
+   */
+  virtual void TraceAll (std::ostream &os, const TraceContext &context) = 0;
+protected:
+  /**
+   * \param path a namespace path
+   * \returns the initial element of the path.
+   *
+   * If the input path is "/foo/...", the return
+   * value is "foo".
+   */
+  std::string GetElement (std::string path);
+  /**
+   * \param path a namespace path
+   * \returns the subpath.
+   *
+   * If the input path is "/foo/bar/...", the return
+   * value is "/bar/...".
+   */
+  std::string GetSubpath (std::string path);
+private:
+  uint32_t m_count;
+};
+
+}//namespace ns3
+
+#endif /* TRACE_RESOLVER_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/trace-source.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,31 @@
+/* -*- 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 "trace-source.h"
+#include "trace-context.h"
+
+namespace ns3 {
+
+void 
+TraceSource::AddCallback (CallbackBase const & callback)
+{
+  AddCallback (callback, TraceContext ());
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/trace-source.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,61 @@
+/* -*- 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
+ * 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 TRACE_SOURCE_H
+#define TRACE_SOURCE_H
+
+#include <ostream>
+
+namespace ns3 {
+
+class CallbackBase;
+class TraceContext;
+
+/**
+ * \brief the base class for all trace sources
+ *
+ * Every trace source which wishes to be connectable and disconnectable with
+ * the TraceResolver system should derive from this base class and implement
+ * all three methods below.
+ */
+class TraceSource
+{
+public:
+  virtual ~TraceSource () {}
+  /**
+   * \param callback the callback to connect to this trace source
+   * \param context the context associated to the input callback which should be passed
+   *        back to the user.
+   */
+  virtual void AddCallback (CallbackBase const & callback, TraceContext const & context) = 0;
+  /**
+   * \param callback the callback to connect to this trace source
+   */
+  void AddCallback (CallbackBase const & callback);
+  /**
+   * \param callback the callback to disconnect from this trace source
+   */
+  virtual void RemoveCallback (CallbackBase const & callback) = 0;
+  virtual void ConnectPrinter (std::ostream &os, TraceContext const &context) = 0;
+};
+
+} // namespace ns3
+
+#endif /* TRACE_SOURCE_H */
--- a/src/core/type-name.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/type-name.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -22,4 +22,5 @@
 DEF_TYPE (float);
 DEF_TYPE (double);
 
+
 }//namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/type-traits.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,26 @@
+#ifndef TYPE_TRAITS_H
+#define TYPE_TRAITS_H
+
+template <typename T>
+struct TypeTraits;
+
+template <typename T>
+struct TypeTraits
+{
+  typedef T ReferencedType;
+};
+
+template <typename T>
+struct TypeTraits<const T &>
+{
+  typedef T ReferencedType;
+};
+
+template <typename T>
+struct TypeTraits<T &>
+{
+  typedef T ReferencedType;
+};
+
+
+#endif /* TYPE_TRAITS_H */
--- a/src/core/uid-manager.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/uid-manager.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -19,7 +19,8 @@
  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
  */
 #include "uid-manager.h"
-#include "ns3/fatal-error.h"
+#include "fatal-error.h"
+#include "assert.h"
 
 
 namespace ns3 {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/uv-trace-source.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,249 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 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
+ * 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 UV_TRACE_SOURCE_H
+#define UV_TRACE_SOURCE_H
+
+#include "callback-trace-source.h"
+#include "trace-source.h"
+#include <stdint.h>
+
+namespace ns3 {
+
+class UVTraceSourceBase : public TraceSource {
+public:
+  typedef CallbackTraceSource<uint64_t, uint64_t> ChangeNotifyCallback;
+
+  UVTraceSourceBase ()
+      : m_callback () {}
+  /* We don't want to copy the base callback. Only setCallback on
+   * a specific instance will do something to it. */
+  UVTraceSourceBase (UVTraceSourceBase const &o) 
+      : m_callback () {}
+  UVTraceSourceBase &operator = (UVTraceSourceBase const &o) {
+      return *this;
+  }
+  ~UVTraceSourceBase () {}
+
+  virtual void AddCallback (CallbackBase const & callback, TraceContext const & context) {
+    m_callback.AddCallback (callback, context);
+  }
+  virtual void RemoveCallback (CallbackBase const & callback) {
+    m_callback.RemoveCallback (callback);  
+  }  
+  virtual void ConnectPrinter (std::ostream &os, const TraceContext &context) {
+    m_callback.ConnectPrinter (os, context);
+  }
+
+protected:
+  void Notify (uint64_t oldVal, uint64_t newVal) {
+      if (oldVal != newVal) 
+        {
+          m_callback (oldVal, newVal);
+        }
+  }
+private:
+  ChangeNotifyCallback m_callback;
+};
+
+template <typename T>
+class SVTraceSource;
+
+
+/**
+ * \brief trace variables of type "unsigned integer"
+ * \ingroup tracing
+ *
+ * This template class implements a POD type: it
+ * behaves like any other variable of type "unsigned integer"
+ * except that it also reports any changes to its
+ * value with its internal callback.
+ *
+ * To instantiate a 32-bit unsigned variable (to store
+ * a TCP counter for example), you would create a variable of type
+ * ns3::UVTraceSource<uint32_t> :
+ \code
+ #include <stdint.h>
+ #include "uv-trace-source.h"
+
+ ns3::UVTraceSource<uint32_t> var;
+ \endcode
+ * and you would use it like any other variable of type uint32_t:
+ \code
+ var += 12;
+ var = 10;
+ \endcode
+ */
+template <typename T>
+class UVTraceSource : public UVTraceSourceBase {
+public:
+  UVTraceSource ()
+      : m_var ()
+  {}
+  UVTraceSource (T const &var) 
+      : m_var (var)
+  {}
+
+  UVTraceSource &operator = (UVTraceSource const &o) {
+      Assign (o.Get ());
+      return *this;
+  }
+  template <typename TT>
+  UVTraceSource &operator = (UVTraceSource<TT> const &o) {
+      Assign (o.Get ());
+      return *this;
+  }
+  template <typename TT>
+  UVTraceSource &operator = (SVTraceSource<TT> const &o) {
+      Assign (o.Get ());
+      return *this;
+  }
+  UVTraceSource &operator++ () {
+      Assign (Get () + 1);
+      return *this;
+  }
+  UVTraceSource &operator-- () {
+      Assign (Get () - 1);
+      return *this;
+  }
+  UVTraceSource operator++ (int) {
+      UVTraceSource old (*this);
+      ++*this;
+      return old;
+  }
+  UVTraceSource operator-- (int) {
+      UVTraceSource old (*this);
+      --*this;
+      return old;
+  }
+  operator T () const {
+      return Get ();
+  }
+
+
+  void Assign (T var) {
+      Notify (m_var, var);
+      m_var = var;
+  }
+  T Get (void) const {
+      return m_var;
+  }
+
+private:
+  T m_var;
+};
+
+template <typename T>
+UVTraceSource<T> &operator += (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
+  lhs.Assign (lhs.Get () + rhs.Get ());
+  return lhs;
+}
+template <typename T>
+UVTraceSource<T> &operator -= (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
+  lhs.Assign (lhs.Get () - rhs.Get ());
+  return lhs;
+}
+template <typename T>
+UVTraceSource<T> &operator *= (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
+  lhs.Assign (lhs.Get () * rhs.Get ());
+  return lhs;
+}
+template <typename T>
+UVTraceSource<T> &operator /= (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
+  lhs.Assign (lhs.Get () / rhs.Get ());
+  return lhs;
+}
+template <typename T>
+UVTraceSource<T> &operator <<= (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
+  lhs.Assign (lhs.Get () << rhs.Get ());
+  return lhs;
+}
+template <typename T>
+UVTraceSource<T> &operator >>= (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
+  lhs.Assign (lhs.Get () >> rhs.Get ());
+  return lhs;
+}
+template <typename T>
+UVTraceSource<T> &operator &= (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
+  lhs.Assign (lhs.Get () & rhs.Get ());
+  return lhs;
+}
+template <typename T>
+UVTraceSource<T> &operator |= (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
+  lhs.Assign (lhs.Get () | rhs.Get ());
+  return lhs;
+}
+template <typename T>
+UVTraceSource<T> &operator ^= (UVTraceSource<T> &lhs, UVTraceSource<T> const &rhs) {
+  lhs.Assign (lhs.Get () ^ rhs.Get ());
+  return lhs;
+}
+
+
+template <typename T, typename U>
+UVTraceSource<T> &operator += (UVTraceSource<T> &lhs, U const &rhs) {
+  lhs.Assign (lhs.Get () + rhs);
+  return lhs;
+}
+template <typename T, typename U>
+UVTraceSource<T> &operator -= (UVTraceSource<T> &lhs, U const &rhs) {
+  lhs.Assign (lhs.Get () - rhs);
+  return lhs;
+}
+template <typename T, typename U>
+UVTraceSource<T> &operator *= (UVTraceSource<T> &lhs, U const &rhs) {
+  lhs.Assign (lhs.Get () * rhs);
+  return lhs;
+}
+template <typename T, typename U>
+UVTraceSource<T> &operator /= (UVTraceSource<T> &lhs, U const &rhs) {
+  lhs.Assign (lhs.Get () / rhs);
+  return lhs;
+}
+template <typename T, typename U>
+UVTraceSource<T> &operator <<= (UVTraceSource<T> &lhs, U const &rhs) {
+  lhs.Assign (lhs.Get () << rhs);
+  return lhs;
+}
+template <typename T, typename U>
+UVTraceSource<T> &operator >>= (UVTraceSource<T> &lhs, U const &rhs) {
+  lhs.Assign (lhs.Get () >> rhs);
+  return lhs;
+}
+template <typename T, typename U>
+UVTraceSource<T> &operator &= (UVTraceSource<T> &lhs, U const &rhs) {
+  lhs.Assign (lhs.Get () & rhs);
+  return lhs;
+}
+template <typename T, typename U>
+UVTraceSource<T> &operator |= (UVTraceSource<T> &lhs, U const &rhs) {
+  lhs.Assign (lhs.Get () | rhs);
+  return lhs;
+}
+template <typename T, typename U>
+UVTraceSource<T> &operator ^= (UVTraceSource<T> &lhs, U const &rhs) {
+  lhs.Assign (lhs.Get () ^ rhs);
+  return lhs;
+}
+
+}; // namespace ns3
+
+#endif /* UV_TRACE_SOURCE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/variable-tracer-test.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,272 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 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
+ * 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 "uv-trace-source.h"
+#include "sv-trace-source.h"
+#include "trace-context.h"
+#include "test.h"
+#include "callback.h"
+
+
+namespace ns3 {
+
+class Foo {
+public:
+  void Notify (TraceContext const &contex, uint64_t oldVal, uint64_t newVal) {}
+};
+
+class VariableTracerTest: public Test {
+public:
+  VariableTracerTest ();
+  void RunUnsignedTests (void);
+  void RunSignedUnsignedTests (void);
+  virtual bool RunTests (void);
+};
+void
+VariableTracerTest::RunUnsignedTests (void)
+{
+  UVTraceSource<uint32_t> var, ovar, tmp;
+  uint32_t utmp;
+  Foo *foo = new Foo ();
+  
+  var.AddCallback (MakeCallback (&Foo::Notify, foo), TraceContext ());
+
+  var = 10;
+  ovar = var;
+
+  if (var == ovar) 
+    {
+    }
+  if (var != ovar) 
+    {
+    }
+  if (var > ovar) 
+    {
+    }
+  if (var >= ovar) 
+    {
+    }
+  if (var < ovar)
+    {
+    }
+  
+  if (var <= ovar)
+
+  if (var == 1)
+    {
+    }
+  if (var != 1)
+    {
+    }
+  if (var > 1)
+    {
+    }
+  if (var >= 1)
+    {
+    }
+  if (var < 1)
+    {
+    }
+  if (var <= 1)
+    {
+    }
+
+  if (1 == ovar)
+    {
+    }
+  if (1 != ovar)
+    {
+    }
+  if (1 > ovar)
+    {
+    }
+  if (1 >= ovar)
+    {
+    }
+  if (1 < ovar)
+    {
+    }
+  if (1 <= ovar)
+    {
+    }
+
+  var++;
+  ++var;
+  var--;
+  --var;
+
+  tmp = var + ovar;
+  tmp = var - ovar;
+  tmp = var / ovar;
+  tmp = var * ovar;
+  tmp = var << ovar;
+  tmp = var >> ovar;
+  tmp = var & ovar;
+  tmp = var | ovar;
+  tmp = var ^ ovar;
+
+  tmp = var + 1;
+  tmp = var - 1;
+  tmp = var / 1;
+  tmp = var * 1;
+  tmp = var << 1;
+  tmp = var >> 1;
+  tmp = var & 1;
+  tmp = var | 1;
+  tmp = var ^ 1;
+
+  tmp = 1 + ovar;
+  tmp = 1 - ovar;
+  tmp = 1 / ovar;
+  tmp = 1 * ovar;
+  tmp = 1 << ovar;
+  tmp = 1 >> ovar;
+  tmp = 1 & ovar;
+  tmp = 1 | ovar;
+  tmp = 1 ^ ovar;
+
+  tmp += var;
+  tmp -= var;
+  tmp /= var;
+  tmp *= var;
+  tmp <<= var;
+  tmp >>= var;
+  tmp &= var;
+  tmp |= var;
+  tmp ^= var;
+
+  tmp += 1;
+  tmp -= 1;
+  tmp /= 1;
+  tmp *= 1;
+  tmp <<= 1;
+  tmp >>= 1;
+  tmp &= 1;
+  tmp |= 1;
+  tmp ^= 1;
+
+
+  utmp = var + ovar;
+  utmp = var - ovar;
+  utmp = var / ovar;
+  utmp = var * ovar;
+  utmp = var << ovar;
+  utmp = var >> ovar;
+  utmp = var & ovar;
+  utmp = var | ovar;
+  utmp = var ^ ovar;
+
+  utmp = var + 1;
+  utmp = var - 1;
+  utmp = var / 1;
+  utmp = var * 1;
+  utmp = var << 1;
+  utmp = var >> 1;
+  utmp = var & 1;
+  utmp = var | 1;
+  utmp = var ^ 1;
+
+  utmp = 1 + ovar;
+  utmp = 1 - ovar;
+  utmp = 1 / ovar;
+  utmp = 1 * ovar;
+  utmp = 1 << ovar;
+  utmp = 1 >> ovar;
+  utmp = 1 & ovar;
+  utmp = 1 | ovar;
+  utmp = 1 ^ ovar;
+
+  utmp += var;
+  utmp -= var;
+  utmp /= var;
+  utmp *= var;
+  utmp <<= var;
+  utmp >>= var;
+  utmp &= var;
+  utmp |= var;
+  utmp ^= var;
+
+  utmp += 1;
+  utmp -= 1;
+  utmp /= 1;
+  utmp *= 1;
+  utmp <<= 1;
+  utmp >>= 1;
+  utmp &= 1;
+  utmp |= 1;
+  utmp ^= 1;
+
+  delete foo;
+}
+
+void
+VariableTracerTest::RunSignedUnsignedTests (void)
+{
+  unsigned short utmp = 10;
+  unsigned int uitmp = 7;
+  short stmp = 5;
+  utmp = stmp;
+  utmp += stmp;
+  uitmp = utmp;
+  utmp = uitmp;
+
+  UVTraceSource<unsigned short> uvar = 10;
+  UVTraceSource<unsigned int> uivar = 5;
+  SVTraceSource<short> svar = 5;
+  SVTraceSource<int> sivar = 5;
+  uvar = svar;
+  svar = uvar;
+  uvar += svar;
+  svar += uvar;
+
+  uvar = sivar;
+  sivar = uvar;
+  uvar += sivar;
+  sivar += uvar;
+
+  uivar = uvar;
+  uvar = uivar;
+  uivar += uvar;
+  uvar += uivar;
+
+  sivar = svar;
+  svar = sivar;
+  sivar += svar;
+  svar += sivar;
+}
+
+bool 
+VariableTracerTest::RunTests (void)
+{
+  RunUnsignedTests ();
+  RunSignedUnsignedTests ();
+
+  return true;
+}
+
+VariableTracerTest::VariableTracerTest ()
+  : Test ("VariableTracer") {}
+
+static VariableTracerTest gVariableTracerTest;
+
+}; // namespace ns3
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/waf	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,1 @@
+exec "`dirname "$0"`"/../../waf "$@"
\ No newline at end of file
--- a/src/core/wscript	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/core/wscript	Fri Sep 28 11:59:46 2007 +0100
@@ -3,8 +3,6 @@
 
 
 def configure(conf):
-    conf.env.append_value('NS3_MODULES', 'ns3-core')
-
     e = conf.create_header_configurator()
     e.mandatory = False
     e.name = 'stdlib.h'
@@ -17,18 +15,23 @@
     e.define = 'HAVE_GETENV'
     e.run()
 
+    e = conf.create_header_configurator()
+    e.mandatory = False
+    e.name = 'signal.h'
+    e.define = 'HAVE_SIGNAL_H'
+    e.run()
+
     conf.write_config_header('ns3/core-config.h')
 
 
 
 def build(bld):
-    core = bld.create_obj('cpp', 'shlib')
-    core.name = 'ns3-core'
-    core.target = core.name
+    core = bld.create_ns3_module('core')
     core.source = [
         'callback-test.cc',
         'debug.cc',
-        'assert.cc',
+        'log.cc',
+        'breakpoint.cc',
         'ptr.cc',
         'object.cc',
         'test.cc',
@@ -39,6 +42,15 @@
         'command-line.cc',
         'type-name.cc',
         'component-manager.cc',
+        'random-variable-default-value.cc',
+        'variable-tracer-test.cc',
+        'trace-context.cc',
+        'trace-context-element.cc',
+        'trace-resolver.cc',
+        'callback-trace-source.cc',
+        'composite-trace-resolver.cc',
+        'trace-doc.cc',
+        'trace-source.cc',
         ]
 
     if sys.platform == 'win32':
@@ -58,7 +70,9 @@
         'ptr.h',
         'object.h',
         'debug.h',
+        'log.h',
         'assert.h',
+        'breakpoint.h',
         'fatal-error.h',
         'test.h',
         'random-variable.h',
@@ -67,5 +81,18 @@
         'command-line.h',
         'type-name.h',
         'component-manager.h',
+        'type-traits.h',
+        'random-variable-default-value.h',
+        'trace-source.h',
+        'uv-trace-source.h',
+        'sv-trace-source.h',
+        'fv-trace-source.h',
+        'callback-trace-source.h',
+        'trace-context.h',
+        'trace-context-element.h',
+        'trace-resolver.h',
+        'composite-trace-resolver.h',
+        'array-trace-resolver.h',
+        'trace-doc.h',
         ]
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/backoff.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,83 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007, Emmanuelle Laprise
+ * 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
+ * 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+ */
+
+#include "backoff.h"
+
+namespace ns3 {
+
+Backoff::Backoff() 
+{
+  m_slotTime = MicroSeconds(1);
+  m_minSlots = 1;
+  m_maxSlots = 1000;
+  m_ceiling = 10;
+  m_maxRetries = 1000;
+
+  ResetBackoffTime();
+}
+
+Backoff::Backoff(Time slotTime, uint32_t minSlots, uint32_t maxSlots,
+                 uint32_t ceiling, uint32_t maxRetries)
+{
+  m_slotTime = slotTime;
+  m_minSlots = minSlots;
+  m_maxSlots = maxSlots;
+  m_ceiling = ceiling;
+  m_maxRetries = maxRetries;
+}  
+
+Time
+Backoff::GetBackoffTime (void)
+{
+  Time backoff;
+  uint32_t ceiling;
+
+  if ((m_ceiling > 0) &&(m_numBackoffRetries > m_ceiling))
+    ceiling = m_ceiling;
+  else
+    ceiling = m_numBackoffRetries;
+
+  uint32_t minSlot = m_minSlots;
+  uint32_t maxSlot = (uint32_t)pow(2, ceiling) - 1;
+  if (maxSlot > m_maxSlots)
+    maxSlot = m_maxSlots;
+
+  uint32_t backoffSlots = 
+    (uint32_t)UniformVariable::GetSingleValue(minSlot, maxSlot);
+
+  backoff = Scalar(backoffSlots) * m_slotTime;
+  return (backoff);
+}
+
+void Backoff::ResetBackoffTime (void)
+{
+  m_numBackoffRetries = 0;
+}
+
+bool Backoff::MaxRetriesReached(void) {
+  return (m_numBackoffRetries >= m_maxRetries);
+}
+
+void Backoff::IncrNumRetries(void) {
+  m_numBackoffRetries++;
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/backoff.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,87 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise
+ *
+ * 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca
+ * Derived from the p2p net device file
+Transmi */
+
+#ifndef BACKOFF_H
+#define BACKOFF_H
+
+#include <stdint.h>
+#include "ns3/nstime.h"
+#include "ns3/random-variable.h"
+
+namespace ns3 {
+
+  /**
+   * \brief The backoff class is used for calculating backoff times
+   * when many net devices can write to the same channel
+   *
+   */
+
+class Backoff {
+public:
+  uint32_t m_minSlots; // Minimum number of backoff slots (when
+                       // multiplied by m_slotTime, determines minimum
+                       // backoff time)
+  uint32_t m_maxSlots; // Maximim number of backoff slots (when
+                       // multiplied by m_slotTime, determines
+                       // maximum backoff time)
+  uint32_t m_ceiling;  // Caps the exponential function when the
+                       // number of retries reaches m_ceiling
+  uint32_t m_maxRetries; // Maximum number of transmission retries
+                         // before the packet is dropped.
+  Time     m_slotTime; // Length of one slot. A slot time, it usually
+                       // the packet transmission time, if the packet
+                       // size is fixed.
+
+  Backoff();
+  Backoff(Time slotTime, uint32_t minSlots, uint32_t maxSlots, 
+          uint32_t ceiling, uint32_t maxRetries);
+
+  /**
+   * \return The amount of time that the net device should wait before
+   * trying to retransmit the packet
+   */
+  Time GetBackoffTime();
+  /**
+   * Indicates to the backoff object that the last packet was
+   * successfully transmitted and that the number of retries should be
+   * reset to 0.
+   */
+  void ResetBackoffTime();
+  /**
+   * \return True if the maximum number of retries has been reached
+   */
+  bool MaxRetriesReached();
+  /**
+   * Increments the number of retries by 1.
+   */
+  void IncrNumRetries();
+
+private:
+  uint32_t m_numBackoffRetries; // Number of times that the
+                                // transmitter has tried to
+                                // unsuccessfully transmit the current
+                                // packet
+};
+
+}; // namespace ns3
+
+#endif // BACKOFF_H
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/csma-channel.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,374 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise
+ * 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
+ * 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+ */
+
+#include "csma-channel.h"
+#include "csma-net-device.h"
+#include "ns3/packet.h"
+#include "ns3/simulator.h"
+#include "ns3/log.h"
+
+NS_LOG_COMPONENT_DEFINE ("CsmaChannel");
+
+namespace ns3 {
+
+CsmaDeviceRec::CsmaDeviceRec()
+{
+  active = false;
+}
+
+CsmaDeviceRec::CsmaDeviceRec(Ptr<CsmaNetDevice> device)
+{
+  devicePtr = device; 
+  active = true;
+}
+
+bool
+CsmaDeviceRec::IsActive() {
+  return active;
+}
+
+
+//
+// By default, you get a channel with the name "Csma Channel" that 
+// has an "infitely" fast transmission speed and zero delay.
+CsmaChannel::CsmaChannel()
+: 
+  Channel ("Csma Channel"), 
+  m_bps (DataRate(0xffffffff)),
+  m_delay (Seconds(0))
+{
+  NS_LOG_FUNCTION;
+  Init();
+}
+
+CsmaChannel::CsmaChannel(
+  const DataRate& bps, 
+  const Time& delay)
+: 
+  Channel ("Csma Channel"), 
+  m_bps (bps),
+  m_delay (delay)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << Channel::GetName() << ", " << bps.GetBitRate() << 
+    ", " << delay << ")");
+  Init();
+}
+
+CsmaChannel::CsmaChannel(
+  const std::string& name,
+  const DataRate& bps, 
+  const Time& delay)
+: 
+  Channel (name),
+  m_bps (bps), 
+  m_delay (delay)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << name << ", " << bps.GetBitRate() << ", " << delay << 
+    ")");
+  Init();
+}
+
+void CsmaChannel::Init() {
+  m_state = IDLE;
+  m_deviceList.clear();
+}
+
+int32_t
+CsmaChannel::Attach(Ptr<CsmaNetDevice> device)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << device << ")");
+  NS_ASSERT(device != 0);
+
+  CsmaDeviceRec rec(device);
+  
+  m_deviceList.push_back(rec);
+  return (m_deviceList.size() - 1);
+}
+
+bool
+CsmaChannel::Reattach(Ptr<CsmaNetDevice> device)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << device << ")");
+  NS_ASSERT(device != 0);
+
+  std::vector<CsmaDeviceRec>::iterator it;
+  for (it = m_deviceList.begin(); it < m_deviceList.end(); it++) 
+    {
+      if (it->devicePtr == device) 
+        {
+          if (!it->active) 
+            {
+              it->active = true;
+              return true;
+            } 
+          else 
+            {
+              return false;
+            }
+        }
+    }
+  return false;
+}
+
+bool
+CsmaChannel::Reattach(uint32_t deviceId)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << deviceId << ")");
+
+  if (deviceId < m_deviceList.size())
+    {
+      return false;
+    }
+
+  if (m_deviceList[deviceId].active)
+    {
+      return false;
+    } 
+  else 
+    {
+      m_deviceList[deviceId].active = true;
+      return true;
+    }
+}
+
+bool
+CsmaChannel::Detach(uint32_t deviceId)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << deviceId << ")");
+
+  if (deviceId < m_deviceList.size())
+    {
+      if (!m_deviceList[deviceId].active)
+        {
+          NS_LOG_WARN ("CsmaChannel::Detach Device is already detached (" << 
+            deviceId << ")");
+          return false;
+        }
+
+      m_deviceList[deviceId].active = false;
+      if ((m_state == TRANSMITTING) && (m_currentSrc == deviceId))
+        {
+          NS_LOG_WARN ("CsmaChannel::Detach Device is currently" << 
+            "transmitting (" << deviceId << ")");
+          // Here we will need to place a warning in the packet
+        }
+
+      return true;
+    } 
+  else 
+    {
+      return false;
+    }
+}
+
+bool
+CsmaChannel::Detach(Ptr<CsmaNetDevice> device)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << device << ")");
+  NS_ASSERT(device != 0);
+
+  std::vector<CsmaDeviceRec>::iterator it;
+  for (it = m_deviceList.begin(); it < m_deviceList.end(); it++) 
+    {
+      if ((it->devicePtr == device) && (it->active)) 
+        {
+          it->active = false;
+          return true;
+        }
+    }
+  return false;
+}
+
+bool
+CsmaChannel::TransmitStart(Packet& p, uint32_t srcId)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << &p << ", " << srcId << ")");
+  NS_LOG_INFO ("UID is " << p.GetUid () << ")");
+
+  if (m_state != IDLE)
+    {
+      NS_LOG_WARN ("state is not IDLE");
+      return false;
+    }
+
+  if (!IsActive(srcId))
+    {
+      NS_LOG_ERROR ("Seclected source is not currently attached to network");
+      return false;
+    }
+
+  NS_LOG_LOGIC ("switch to TRANSMITTING");
+  m_currentPkt = p;
+  m_currentSrc = srcId;
+  m_state = TRANSMITTING;
+  return true;
+}
+
+bool
+CsmaChannel::IsActive(uint32_t deviceId) 
+{
+    return (m_deviceList[deviceId].active);
+}
+
+bool
+CsmaChannel::TransmitEnd()
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << &m_currentPkt << ", " << m_currentSrc << ")");
+  NS_LOG_INFO ("UID is " << m_currentPkt.GetUid () << ")");
+
+  NS_ASSERT(m_state == TRANSMITTING);
+  m_state = PROPAGATING;
+
+  bool retVal = true;
+
+  if (!IsActive(m_currentSrc)) {
+    NS_LOG_ERROR ("Seclected source was detached before the end of the"
+      "transmission");
+    retVal = false;
+  }
+
+  NS_LOG_LOGIC ("Schedule event in " << m_delay.GetSeconds () << " sec");
+
+  Simulator::Schedule (m_delay,
+                       &CsmaChannel::PropagationCompleteEvent,
+                       this);
+  return retVal;
+}
+
+void
+CsmaChannel::PropagationCompleteEvent()
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << &m_currentPkt << ")");
+  NS_LOG_INFO ("UID is " << m_currentPkt.GetUid () << ")");
+
+  NS_ASSERT(m_state == PROPAGATING);
+
+  NS_LOG_LOGIC ("Receive");
+  
+  std::vector<CsmaDeviceRec>::iterator it;
+  for (it = m_deviceList.begin(); it < m_deviceList.end(); it++) 
+    {
+      if (it->IsActive())
+      {
+        it->devicePtr->Receive (m_currentPkt);
+      }
+    }
+  m_state = IDLE;
+}
+
+
+uint32_t 
+CsmaChannel::GetNumActDevices (void)
+{
+  int numActDevices = 0;
+  std::vector<CsmaDeviceRec>::iterator it;
+  for (it = m_deviceList.begin(); it < m_deviceList.end(); it++) 
+    {
+      if (it->active)
+        {
+          numActDevices++;
+        }
+    }
+  return numActDevices;
+}
+
+// This is not the number of active devices. This is the total number
+// of devices even if some were detached after.
+uint32_t 
+CsmaChannel::GetNDevices (void) const
+{
+  return (m_deviceList.size());
+}
+
+Ptr<NetDevice>
+CsmaChannel::GetDevice (uint32_t i) const
+{
+  Ptr< CsmaNetDevice > netDevice;
+
+  netDevice = m_deviceList[i].devicePtr;
+  return netDevice;
+}
+
+int32_t
+CsmaChannel::GetDeviceNum (Ptr<CsmaNetDevice> device)
+{
+  std::vector<CsmaDeviceRec>::iterator it;
+  int i = 0;
+  for (it = m_deviceList.begin(); it < m_deviceList.end(); it++) 
+    {
+      if (it->devicePtr == device)
+        {
+          if (it->active) 
+            {
+              return i;
+            } 
+          else 
+            {
+              return -2;
+            }
+        }
+      i++;
+    }
+  return -1;
+}
+
+bool 
+CsmaChannel::IsBusy (void)
+{
+  if (m_state == IDLE) 
+    {
+      return false;
+    } 
+  else 
+    {
+      return true;
+    }
+}
+
+DataRate
+CsmaChannel::GetDataRate (void)
+{
+  return m_bps;
+}
+
+Time
+CsmaChannel::GetDelay (void)
+{
+  return m_delay;
+}
+
+WireState
+CsmaChannel::GetState(void)
+{
+  return m_state;
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/csma-channel.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,307 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise
+ *
+ * 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: Emmanuelle Laprise<emmanuelle.laprise@bluekazoo.ca>
+ */
+
+#ifndef CSMA_CHANNEL_H
+#define CSMA_CHANNEL_H
+
+#include "ns3/channel.h"
+#include "ns3/ptr.h"
+#include "ns3/packet.h"
+#include "ns3/nstime.h"
+#include "ns3/data-rate.h"
+
+namespace ns3 {
+
+class CsmaNetDevice;
+
+  /**
+   * \brief CsmaNetDevice Record 
+   *
+   * Stores the information related to each net device that is
+   * connected to the channel. 
+   */
+  class CsmaDeviceRec {
+  public:
+    Ptr< CsmaNetDevice > devicePtr; /// Pointer to the net device
+    bool                       active;    /// Is net device enabled to TX/RX
+
+    CsmaDeviceRec();
+    CsmaDeviceRec(Ptr< CsmaNetDevice > device);
+    /*
+     * \return If the net device pointed to by the devicePtr is active
+     * and ready to RX/TX.
+     */
+    bool IsActive();                   
+  };
+
+  /**
+   * Current state of the channel
+   */ 
+  enum WireState
+    {
+      IDLE,          /**< Channel is IDLE, no packet is being
+                        transmitted */
+      TRANSMITTING,  /**< Channel is BUSY, a packet is being written
+                        by a net device */
+      PROPAGATING    /**< Channel is BUSY, packet is propagating to
+                        all attached net devices */
+    };
+
+/**
+ * \brief Csma Channel.
+ *
+ * This class represents a simple Csma channel that can be used
+ * when many nodes are connected to one wire. It uses a single busy
+ * flag to indicate if the channel is currently in use. It does not
+ * take into account the distances between stations or the speed of
+ * light to determine collisions.
+ *
+ * Each net device must query the state of the channel and make sure
+ * that it is IDLE before writing a packet to the channel.
+ *
+ * When the channel is instaniated, the constructor takes parameters
+ * for a single speed, in bits per second, and a speed-of-light delay
+ * time as a Time object.  When a net device is attached to a channel,
+ * it is assigned a device ID, this is in order to facilitate the
+ * check that makes sure that a net device that is trying to send a
+ * packet to the channel is really connected to this channel
+ *
+ */
+class CsmaChannel : public Channel {
+public:
+  /**
+   * \brief Create a CsmaChannel
+   *
+   * By default, you get a channel with the name "Csma Channel" that
+   * has an "infitely" fast transmission speed and zero delay.
+   */
+  CsmaChannel ();
+  
+  /**
+   * \brief Create a CsmaChannel
+   *
+   * \param bps The bitrate of the channel
+   * \param delay Transmission delay through the channel
+   */  
+  CsmaChannel (const DataRate& bps, const Time& delay);
+  
+  /**
+   * \brief Create a CsmaChannel
+   *
+   * \param name the name of the channel for identification purposes
+   * \param bps The bitrate of the channel
+   * \param delay Transmission delay through the channel
+   */
+  CsmaChannel (const std::string& name,
+                     const DataRate& bps, const Time& delay);
+
+  /**
+   * \brief Attach a given netdevice to this channel
+   *
+   * \param device Device pointer to the netdevice to attach to the channel
+   * \return The assigned device number
+   */
+  int32_t Attach (Ptr<CsmaNetDevice> device);
+  /**
+   * \brief Detach a given netdevice from this channel
+   *
+   * The net device is marked as inactive and it is not allowed to
+   * receive or transmit packets
+   *
+   * \param device Device pointer to the netdevice to detach from the channel
+   * \return True if the device is found and attached to the channel,
+   * false if the device is not currently connected to the channel or
+   * can't be found.
+   */
+  bool Detach (Ptr<CsmaNetDevice> device);
+  /**
+   * \brief Detach a given netdevice from this channel
+   *
+   * The net device is marked as inactive and it is not allowed to
+   * receive or transmit packets
+   *
+   * \param deviceId The deviceID assigned to the net device when it
+   * was connected to the channel
+   * \return True if the device is found and attached to the channel,
+   * false if the device is not currently connected to the channel or
+   * can't be found.
+   */
+  bool Detach (uint32_t deviceId);
+  /**
+   * \brief Reattach a previously detached net device to the channel
+   *
+   * The net device is marked as active. It is now allowed to receive
+   * or transmit packets. The net device must have been previously
+   * attached to the channel using the attach function.
+   *
+   * \param deviceId The device ID assigned to the net device when it
+   * was connected to the channel
+   * \return True if the device is found and is not attached to the
+   * channel, false if the device is currently connected to the
+   * channel or can't be found.
+   */
+  bool Reattach(uint32_t deviceId);
+  /**
+   * \brief Reattach a previously detached net device to the channel
+   *
+   * The net device is marked as active. It is now allowed to receive
+   * or transmit packets. The net device must have been previously
+   * attached to the channel using the attach function.
+   *
+   * \param device Device pointer to the netdevice to detach from the channel
+   * \return True if the device is found and is not attached to the
+   * channel, false if the device is currently connected to the
+   * channel or can't be found.
+   */
+  bool Reattach(Ptr<CsmaNetDevice> device);
+  /**
+   * \brief Start transmitting a packet over the channel
+   *
+   * If the srcId belongs to a net device that is connected to the
+   * channel, packet transmission begins, and the channel becomes busy
+   * until the packet has completely reached all destinations.
+   *
+   * \param p A reference to the packet that will be transmitted over
+   * the channel
+   * \param srcId The device Id of the net device that wants to
+   * transmit on the channel.
+   * \return True if the channel is not busy and the transmitting net
+   * device is currently active.
+   */
+  bool TransmitStart (Packet& p, uint32_t srcId);
+  /**
+   * \brief Indicates that the net device has finished transmitting
+   * the packet over the channel
+   *
+   * The channel will stay busy until the packet has completely
+   * propagated to all net devices attached to the channel. The
+   * TransmitEnd function schedules the PropagationCompleteEvent which
+   * will free the channel for further transmissions. Stores the
+   * packet p as the m_currentPkt, the packet being currently
+   * transmitting.
+   *
+   * \return Returns true unless the source was detached before it
+   * completed its transmission.
+   */
+  bool TransmitEnd ();
+  /**
+   * \brief Indicates that the channel has finished propagating the
+   * current packet. The channel is released and becomes free.
+   *
+   * Calls the receive function of every active net device that is
+   * attached to the channel.
+   */
+  void PropagationCompleteEvent();
+  /**
+   * \return Returns the device number assigned to a net device by the
+   * channel
+   *
+   * \param device Device pointer to the netdevice for which the device
+   * number is needed
+   */
+  int32_t GetDeviceNum (Ptr<CsmaNetDevice> device);
+  /**
+   * \return Returns the state of the channel (IDLE -- free,
+   * TRANSMITTING -- busy, PROPAGATING - busy )
+   */
+  WireState GetState();
+
+  /**
+   * \brief Indicates if the channel is busy. The channel will only
+   * accept new packets for transmission if it is not busy.
+   *
+   * \return Returns true if the channel is busy and false if it is
+   * free.
+   */
+  bool IsBusy();
+  
+  /**
+   * \brief Indicates if a net device is currently attached or
+   * detached from the channel.
+   *
+   * \param deviceId The ID that was assigned to the net device when
+   * it was attached to the channel.
+   * \return Returns true if the net device is attached to the
+   * channel, false otherwise.
+   */
+  bool IsActive(uint32_t deviceId);
+  /**
+   * \return Returns the number of net devices that are currently
+   * attached to the channel.
+   */
+  uint32_t GetNumActDevices (void);
+  /**
+   * \return Returns the total number of devices including devices
+   * that have been detached from the channel.
+   */
+  virtual uint32_t GetNDevices (void) const;
+  /**
+   * \param i The deviceId of the net device for which we want the
+   * pointer.
+   * \return Returns the pointer to the net device that is associated
+   * with deviceId i.
+   */
+  virtual Ptr<NetDevice> GetDevice (uint32_t i) const;
+
+  virtual DataRate GetDataRate (void);
+  virtual Time GetDelay (void);
+
+private:
+  DataRate      m_bps;    /// Data rate of the channel
+  Time          m_delay;  /// Delay of the channel.
+
+  /**
+   * List of the net devices that have been or are currently connected
+   * to the channel.
+   *
+   * Devices are nor removed from this list, they are marked as
+   * inactive. Otherwise the assigned device IDs will not refer to the
+   * correct NetDevice. The DeviceIds are used so that it is possible
+   * to have a number to refer to an entry in the list so that the
+   * whole list does not have to be searched when making sure that a
+   * source is attached to a channel when it is transmitting data.
+   */
+  std::vector< CsmaDeviceRec >            m_deviceList;
+  /**
+   * Packet that is currently being transmitted on the channel (or last
+   * packet to have been transmitted on the channel if the channel is
+   * free.)
+   */
+  Packet                              m_currentPkt;
+  /**
+   * Device Id of the source that is currently transmitting on the
+   * channel. Or last source to have transmitted a packet on the
+   * channel, if the channel is currently not busy.
+   */
+  uint32_t                            m_currentSrc;
+  /**
+   * Current state of the channel
+   */
+  WireState          m_state;
+  /**
+   * Initializes the channel when it is constructed. Resets the
+   * deviceList and sets the channel state to IDLE.
+   */
+  void Init (void);
+};
+
+} // namespace ns3
+
+#endif /* CSMA_CHANNEL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/csma-ipv4-topology.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,151 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+//
+// Copyright (c) 2007 Emmanuelle Laprise
+//
+// 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+//
+
+#include <algorithm>
+#include "ns3/assert.h"
+#include "ns3/fatal-error.h"
+#include "ns3/nstime.h"
+#include "ns3/internet-node.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/ipv4.h"
+#include "ns3/queue.h"
+
+#include "csma-channel.h"
+#include "csma-net-device.h"
+#include "csma-ipv4-topology.h"
+
+namespace ns3 {
+
+uint32_t
+CsmaIpv4Topology::AddIpv4CsmaNetDevice(
+  Ptr<Node> node,
+  Ptr<CsmaChannel> channel,
+  Mac48Address addr)
+{
+  Ptr<Queue> q = Queue::CreateDefault ();
+
+  // assume full-duplex
+  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,
+                                     Mac48Address addr)
+{
+  Ptr<Queue> q = Queue::CreateDefault ();
+
+  Ptr<CsmaNetDevice> nd0 = Create<CsmaNetDevice> (n1, addr,
+                                                  ns3::CsmaNetDevice::LLC,
+                                                  true, false);
+  nd0->AddQueue(q);
+  nd0->Attach (ch);
+
+  Ptr<CsmaNetDevice> nd1 = Create<CsmaNetDevice> (n1, addr,
+                                                  ns3::CsmaNetDevice::LLC,
+                                                  false, true);
+  nd1->AddQueue(q);
+  nd1->Attach (ch);
+}
+
+void
+CsmaIpv4Topology::AddIpv4RawCsmaNode(Ptr<Node> n1,
+                                     Ptr<CsmaChannel> ch,
+                                     Mac48Address addr)
+{
+  Ptr<Queue> q = Queue::CreateDefault ();
+
+  Ptr<CsmaNetDevice> nd0 = Create<CsmaNetDevice> (n1, addr,
+                                                  ns3::CsmaNetDevice::RAW,
+                                                  true, false);
+  nd0->AddQueue(q);
+  nd0->Attach (ch);
+
+  Ptr<CsmaNetDevice> nd1 = Create<CsmaNetDevice> (n1, addr,
+                                                  ns3::CsmaNetDevice::RAW,
+                                                  false, true);
+  nd1->AddQueue(q);
+  nd1->Attach (ch);
+}
+
+uint32_t
+CsmaIpv4Topology::AddIpv4Address(
+  Ptr<Node>             node,
+  uint32_t              netDeviceNumber,
+  const Ipv4Address     address,
+  const Ipv4Mask        mask)
+{
+  Ptr<NetDevice> nd = node->GetDevice(netDeviceNumber);
+
+  Ptr<Ipv4> ipv4 = node->QueryInterface<Ipv4> (Ipv4::iid);
+  uint32_t ifIndex = ipv4->AddInterface (nd);
+
+  ipv4->SetAddress (ifIndex, address);
+  ipv4->SetNetworkMask (ifIndex, mask);
+  ipv4->SetUp (ifIndex);
+  return ifIndex;
+}
+
+void
+CsmaIpv4Topology::AddIpv4Routes (
+  Ptr<NetDevice> nd1, Ptr<NetDevice> nd2)
+{ 
+  // Assert that both are Ipv4 nodes
+  Ptr<Ipv4> ip1 = nd1->GetNode ()->QueryInterface<Ipv4> (Ipv4::iid);
+  Ptr<Ipv4> ip2 = nd2->GetNode ()->QueryInterface<Ipv4> (Ipv4::iid);
+  NS_ASSERT(ip1 != 0 && ip2 != 0);
+
+  // Get interface indexes for both nodes corresponding to the right channel
+  uint32_t index1 = 0;
+  bool found = false;
+  for (uint32_t i = 0; i < ip1->GetNInterfaces (); i++)
+    {
+      if (ip1 ->GetNetDevice (i) == nd1)
+        {
+          index1 = i;
+          found = true;
+        }
+    }
+  NS_ASSERT (found);
+
+  uint32_t index2 = 0;
+  found = false;
+  for (uint32_t i = 0; i < ip2->GetNInterfaces (); i++)
+    {
+      if (ip2 ->GetNetDevice (i) == nd2)
+        {
+          index2 = i;
+          found = true;
+        }
+    }
+  NS_ASSERT (found);
+
+  ip1->AddHostRouteTo (ip2-> GetAddress (index2), index1);
+  ip2->AddHostRouteTo (ip1-> GetAddress (index1), index2); 
+}
+
+} // namespace ns3
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/csma-ipv4-topology.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,127 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+//
+// Copyright (c) 2007 Emmanuelle Laprise
+//
+// 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+//
+
+#ifndef __CSMA_IPV4_TOPOLOGY_H__
+#define __CSMA_IPV4_TOPOLOGY_H__
+
+#include "ns3/ptr.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/ipv4.h"
+#include "ns3/ipv4-route.h"
+#include "ns3/internet-node.h"
+#include "ns3/csma-net-device.h"
+
+// The topology class consists of only static methods thar are used to
+// create the topology and data flows for an ns3 simulation
+
+namespace ns3 {
+
+class CsmaIpv4Channel;
+class Node;
+class IPAddr;
+class DataRate;
+class Queue;
+
+/**
+ * \brief A helper class to create Topologies based on the
+ * InternetNodes and CsmaChannels. Either the
+ * SimpleCsmaNetDevice or the LLCCsmaNetDevice can be used
+ * when constructing these topologies.
+ */
+class CsmaIpv4Topology {
+public:
+
+  /**
+   * \param n1 Node to be attached to the Csma channel
+   * \param ch CsmaChannel to which node n1 should be attached
+   * \param addr Mac address of the node
+   *
+   * Add a Csma node to a Csma channel. This function adds
+   * a EthernetCsmaNetDevice to the nodes so that they can
+   * connect to a CsmaChannel. This means that Ethernet headers
+   * and trailers will be added to the packet before sending out on
+   * the net device.
+   * 
+   * \return ifIndex of the device
+   */
+  static uint32_t AddIpv4CsmaNetDevice(Ptr<Node> node,
+                                       Ptr<CsmaChannel> channel,
+                                       Mac48Address addr);
+
+  /**
+   * \param n1 Node to be attached to the Csma channel
+   * \param ch CsmaChannel to which node n1 should be attached
+   * \param addr Mac address of the node
+   *
+   * Add a Csma node to a Csma channel. This function adds
+   * a RawCsmaNetDevice to the nodes so that they can connect
+   * to a CsmaChannel.
+   */
+  static void AddIpv4RawCsmaNode( Ptr<Node> n1,
+                                    Ptr<CsmaChannel> ch,
+                                    Mac48Address addr);
+
+  /**
+   * \param n1 Node to be attached to the Csma channel
+   * \param ch CsmaChannel to which node n1 should be attached
+   * \param addr Mac address of the node
+   *
+   * Add a Csma node to a Csma channel. This function adds
+   * a LlcCsmaNetDevice to the nodes so that they can connect
+   * to a CsmaChannel.
+   */
+  static void AddIpv4LlcCsmaNode( Ptr<Node> n1,
+                                    Ptr<CsmaChannel> ch,
+                                    Mac48Address addr);
+
+
+
+  /** 
+   * \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
+   */
+  static uint32_t AddIpv4Address(Ptr<Node> node,
+                                 uint32_t netDeviceNumber, 
+                                 const Ipv4Address address,
+                                 const Ipv4Mask mask);
+
+  /**
+   * \param nd1 Node
+   * \param nd2 Node
+   * 
+   * Add an IPV4 host route between the two specified net devices
+   */
+  static void AddIpv4Routes (Ptr<NetDevice> nd1, Ptr<NetDevice> nd2);
+};
+
+} // namespace ns3
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/csma-net-device.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,690 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise
+ * 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
+ * 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+ */
+
+#include "ns3/log.h"
+#include "ns3/queue.h"
+#include "ns3/simulator.h"
+#include "ns3/composite-trace-resolver.h"
+#include "csma-net-device.h"
+#include "csma-channel.h"
+#include "ns3/ethernet-header.h"
+#include "ns3/ethernet-trailer.h"
+#include "ns3/llc-snap-header.h"
+
+NS_LOG_COMPONENT_DEFINE ("CsmaNetDevice");
+
+namespace ns3 {
+
+CsmaTraceType::CsmaTraceType (enum Type type)
+  : m_type (type)
+{
+  NS_LOG_FUNCTION;
+}
+
+CsmaTraceType::CsmaTraceType ()
+  : m_type (RX)
+{
+  NS_LOG_FUNCTION;
+}
+
+void 
+CsmaTraceType::Print (std::ostream &os) const
+{
+  switch (m_type) {
+  case RX:
+    os << "dev-rx";
+    break;
+  case DROP:
+    os << "dev-drop";
+    break;
+  }
+}
+
+uint16_t 
+CsmaTraceType::GetUid (void)
+{
+  NS_LOG_FUNCTION;
+  static uint16_t uid = AllocateUid<CsmaTraceType> ("CsmaTraceType");
+  return uid;
+}
+
+std::string 
+CsmaTraceType::GetTypeName (void) const
+{
+  NS_LOG_FUNCTION;
+  return "ns3::CsmaTraceType";
+}
+
+enum CsmaTraceType::Type 
+CsmaTraceType::Get (void) const
+{
+  NS_LOG_FUNCTION;
+  return m_type;
+}
+
+CsmaNetDevice::CsmaNetDevice (Ptr<Node> node)
+  : NetDevice (node, Mac48Address::Allocate ()),
+    m_bps (DataRate (0xffffffff))
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << node << ")");
+  m_encapMode = IP_ARP;
+  Init(true, true);
+}
+
+CsmaNetDevice::CsmaNetDevice (Ptr<Node> node, Mac48Address addr, 
+                              CsmaEncapsulationMode encapMode) 
+  : NetDevice(node, addr), 
+    m_bps (DataRate (0xffffffff))
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << node << ")");
+  m_encapMode = encapMode;
+
+  Init(true, true);
+}
+
+CsmaNetDevice::CsmaNetDevice (Ptr<Node> node, Mac48Address addr, 
+                              CsmaEncapsulationMode encapMode,
+                              bool sendEnable, bool receiveEnable) 
+  : NetDevice(node, addr), 
+    m_bps (DataRate (0xffffffff))
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << node << ")");
+  m_encapMode = encapMode;
+
+  Init(sendEnable, receiveEnable);
+}
+
+CsmaNetDevice::~CsmaNetDevice()
+{
+  NS_LOG_FUNCTION;
+  m_queue = 0;
+}
+
+void 
+CsmaNetDevice::DoDispose ()
+{
+  NS_LOG_FUNCTION;
+  m_channel = 0;
+  NetDevice::DoDispose ();
+}
+
+//
+// Assignment operator for CsmaNetDevice.
+//
+// This uses the non-obvious trick of taking the source net device passed by
+// value instead of by reference.  This causes the copy constructor to be
+// invoked (where the real work is done -- see above).  All we have to do
+// here is to return the newly constructed net device.
+//
+/*
+CsmaNetDevice&
+CsmaNetDevice::operator= (const CsmaNetDevice nd)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << &nd << ")");
+  return *this;
+}
+*/
+
+void 
+CsmaNetDevice::Init(bool sendEnable, bool receiveEnable)
+{
+  NS_LOG_FUNCTION;
+  m_txMachineState = READY;
+  m_tInterframeGap = Seconds(0);
+  m_channel = 0; 
+  m_queue = 0;
+
+  EnableBroadcast (Mac48Address ("ff:ff:ff:ff:ff:ff"));
+  EnableMulticast (Mac48Address ("01:00:5e:00:00:00"));
+
+  SetSendEnable (sendEnable);
+  SetReceiveEnable (receiveEnable);
+}
+
+void
+CsmaNetDevice::SetSendEnable (bool sendEnable)
+{
+  NS_LOG_FUNCTION;
+  m_sendEnable = sendEnable;
+}
+
+void
+CsmaNetDevice::SetReceiveEnable (bool receiveEnable)
+{
+  NS_LOG_FUNCTION;
+  m_receiveEnable = receiveEnable;
+}
+
+bool
+CsmaNetDevice::IsSendEnabled (void)
+{
+  NS_LOG_FUNCTION;
+  return (m_sendEnable);
+}
+
+bool
+CsmaNetDevice::IsReceiveEnabled (void)
+{
+  NS_LOG_FUNCTION;
+  return (m_receiveEnable);
+}
+
+void 
+CsmaNetDevice::SetDataRate (DataRate bps)
+{
+  NS_LOG_FUNCTION;
+  m_bps = bps;
+}
+
+void 
+CsmaNetDevice::SetInterframeGap (Time t)
+{
+  NS_LOG_FUNCTION;
+  m_tInterframeGap = t;
+}
+
+void 
+CsmaNetDevice::SetBackoffParams (Time slotTime, uint32_t minSlots, 
+                                 uint32_t maxSlots, uint32_t ceiling, 
+                                 uint32_t maxRetries)
+{
+  NS_LOG_FUNCTION;
+  m_backoff.m_slotTime = slotTime;
+  m_backoff.m_minSlots = minSlots;
+  m_backoff.m_maxSlots = maxSlots;
+  m_backoff.m_ceiling = ceiling;
+  m_backoff.m_maxRetries = maxRetries;
+}
+
+void 
+CsmaNetDevice::AddHeader (Packet& p, Mac48Address dest,
+                            uint16_t protocolNumber)
+{
+  NS_LOG_FUNCTION;
+  if (m_encapMode == RAW)
+    {
+      return;
+    }
+  EthernetHeader header (false);
+  EthernetTrailer trailer;
+  Mac48Address source = Mac48Address::ConvertFrom (GetAddress ());
+  header.SetSource(source);
+  header.SetDestination(dest);
+
+  uint16_t lengthType = 0;
+  switch (m_encapMode) 
+    {
+    case ETHERNET_V1:
+      lengthType = p.GetSize() + header.GetSerializedSize() + trailer.GetSerializedSize();
+      break;
+    case IP_ARP:
+      lengthType = protocolNumber;
+      break;
+    case LLC: {
+      LlcSnapHeader llc;
+      llc.SetType (protocolNumber);
+      p.AddHeader (llc);
+    } break;
+    case RAW:
+      NS_ASSERT (false);
+      break;
+    }
+  header.SetLengthType (lengthType);
+  p.AddHeader(header);
+  trailer.CalcFcs(p);
+  p.AddTrailer(trailer);
+}
+
+bool 
+CsmaNetDevice::ProcessHeader (Packet& p, uint16_t & param)
+{
+  NS_LOG_FUNCTION;
+  if (m_encapMode == RAW)
+    {
+      return true;
+    }
+  EthernetHeader header (false);
+  EthernetTrailer trailer;
+      
+  p.RemoveTrailer(trailer);
+  trailer.CheckFcs(p);
+  p.RemoveHeader(header);
+
+  if ((header.GetDestination() != GetBroadcast ()) &&
+      (header.GetDestination() != GetAddress ()))
+    {
+      return false;
+    }
+
+  switch (m_encapMode)
+    {
+    case ETHERNET_V1:
+    case IP_ARP:
+      param = header.GetLengthType();
+      break;
+    case LLC: {
+      LlcSnapHeader llc;
+      p.RemoveHeader (llc);
+      param = llc.GetType ();
+    } break;
+    case RAW:
+      NS_ASSERT (false);
+      break;
+    }
+  return true;
+}
+
+bool
+CsmaNetDevice::DoNeedsArp (void) const
+{
+  NS_LOG_FUNCTION;
+  if ((m_encapMode == IP_ARP) || (m_encapMode == LLC))
+    {
+      return true;
+    } 
+  else 
+    {
+      return false;
+    }
+}
+
+bool
+CsmaNetDevice::SendTo (
+  const Packet& packet, 
+  const Address& dest, 
+  uint16_t protocolNumber)
+{
+  NS_LOG_FUNCTION;
+  Packet p = packet;
+  NS_LOG_LOGIC ("p=" << &p);
+  NS_LOG_LOGIC ("UID is " << p.GetUid () << ")");
+
+  NS_ASSERT (IsLinkUp ());
+
+  // Only transmit if send side of net device is enabled
+  if (!IsSendEnabled())
+    return false;
+
+  Mac48Address destination = Mac48Address::ConvertFrom (dest);
+  AddHeader(p, destination, protocolNumber);
+
+  // Place the packet to be sent on the send queue
+  if (m_queue->Enqueue(p) == false )
+    {
+      return false;
+    }
+  // If the device is idle, we need to start a transmission. Otherwise,
+  // the transmission will be started when the current packet finished
+  // transmission (see TransmitCompleteEvent)
+  if (m_txMachineState == READY) 
+    {
+      // Store the next packet to be transmitted
+      if (m_queue->Dequeue (m_currentPkt))
+        {
+          TransmitStart();
+        }
+    }
+  return true;
+}
+
+void
+CsmaNetDevice::TransmitStart ()
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_LOGIC ("m_currentPkt=" << &m_currentPkt);
+  NS_LOG_LOGIC ("UID is " << m_currentPkt.GetUid ());
+//
+// This function is called to start the process of transmitting a packet.
+// We need to tell the channel that we've started wiggling the wire and
+// schedule an event that will be executed when it's time to tell the 
+// channel that we're done wiggling the wire.
+//
+  NS_ASSERT_MSG((m_txMachineState == READY) || (m_txMachineState == BACKOFF), 
+                "Must be READY to transmit. Tx state is: " 
+                << m_txMachineState);
+
+  // Only transmit if send side of net device is enabled
+  if (!IsSendEnabled())
+    return;
+
+  if (m_channel->GetState() != IDLE)
+    { // Channel busy, backoff and rechedule TransmitStart()
+      m_txMachineState = BACKOFF;
+      if (m_backoff.MaxRetriesReached())
+        { // Too many retries reached, abort transmission of packet
+          TransmitAbort();
+        } 
+      else 
+        {
+          m_backoff.IncrNumRetries();
+          Time backoffTime = m_backoff.GetBackoffTime();
+
+          NS_LOG_LOGIC ("Channel busy, backing off for " << 
+            backoffTime.GetSeconds () << " sec");
+
+          Simulator::Schedule (backoffTime, 
+                               &CsmaNetDevice::TransmitStart, 
+                               this);
+        }
+    } 
+  else 
+    {
+      // Channel is free, transmit packet
+      m_txMachineState = BUSY;
+      Time tEvent = Seconds (m_bps.CalculateTxTime(m_currentPkt.GetSize()));
+      
+      NS_LOG_LOGIC ("Schedule TransmitCompleteEvent in " << 
+        tEvent.GetSeconds () << "sec");
+      
+      Simulator::Schedule (tEvent, 
+                           &CsmaNetDevice::TransmitCompleteEvent, 
+                           this);
+      if (!m_channel->TransmitStart (m_currentPkt, m_deviceId))
+        {
+          NS_LOG_WARN ("Channel transmit start did not work at " << 
+            tEvent.GetSeconds () << "sec");
+          m_txMachineState = READY;
+        } 
+      else 
+        {
+          // Transmission success, reset backoff time parameters.
+          m_backoff.ResetBackoffTime();
+        }
+    }
+}
+
+
+void
+CsmaNetDevice::TransmitAbort (void)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_LOGIC ("Pkt UID is " << m_currentPkt.GetUid () << ")");
+
+  // Try to transmit a new packet
+  bool found;
+  found = m_queue->Dequeue (m_currentPkt);
+  NS_ASSERT_MSG(found, "IsEmpty false but no Packet on queue?");
+  m_backoff.ResetBackoffTime();
+  m_txMachineState = READY;
+  TransmitStart ();
+}
+
+void
+CsmaNetDevice::TransmitCompleteEvent (void)
+{
+  NS_LOG_FUNCTION;
+//
+// This function is called to finish the  process of transmitting a packet.
+// We need to tell the channel that we've stopped wiggling the wire and
+// schedule an event that will be executed when it's time to re-enable
+// the transmitter after the interframe gap.
+//
+  NS_ASSERT_MSG(m_txMachineState == BUSY, "Must be BUSY if transmitting");
+  // Channel should be transmitting
+  NS_ASSERT(m_channel->GetState() == TRANSMITTING);
+  m_txMachineState = GAP;
+
+  NS_LOG_LOGIC ("Pkt UID is " << m_currentPkt.GetUid () << ")");
+  m_channel->TransmitEnd (); 
+
+  NS_LOG_LOGIC ("Schedule TransmitReadyEvent in "
+    << m_tInterframeGap.GetSeconds () << "sec");
+
+  Simulator::Schedule (m_tInterframeGap, 
+                       &CsmaNetDevice::TransmitReadyEvent, 
+                       this);
+}
+
+void
+CsmaNetDevice::TransmitReadyEvent (void)
+{
+  NS_LOG_FUNCTION;
+//
+// This function is called to enable the transmitter after the interframe
+// gap has passed.  If there are pending transmissions, we use this opportunity
+// to start the next transmit.
+//
+  NS_ASSERT_MSG(m_txMachineState == GAP, "Must be in interframe gap");
+  m_txMachineState = READY;
+
+  // Get the next packet from the queue for transmitting
+  if (m_queue->IsEmpty())
+    {
+      return;
+    }
+  else
+    {
+      bool found;
+      found = m_queue->Dequeue (m_currentPkt);
+      NS_ASSERT_MSG(found, "IsEmpty false but no Packet on queue?");
+      TransmitStart ();
+    }
+}
+
+Ptr<TraceResolver>
+CsmaNetDevice::GetTraceResolver (void) const
+{
+  NS_LOG_FUNCTION;
+  Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
+  resolver->AddComposite ("queue", m_queue);
+  resolver->AddSource ("rx",
+                       TraceDoc ("receive MAC packet",
+                                 "const Packet &", "packet received"),
+                       m_rxTrace,
+                       CsmaTraceType (CsmaTraceType::RX));
+  resolver->AddSource ("drop",
+                       TraceDoc ("drop MAC packet",
+                                 "const Packet &", "packet dropped"),
+                       m_dropTrace,
+                       CsmaTraceType (CsmaTraceType::DROP));
+  resolver->SetParentResolver (NetDevice::GetTraceResolver ());
+  return resolver;
+}
+
+bool
+CsmaNetDevice::Attach (Ptr<CsmaChannel> ch)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << &ch << ")");
+
+  m_channel = ch;
+
+  m_deviceId = m_channel->Attach(this);
+  m_bps = m_channel->GetDataRate ();
+  m_tInterframeGap = m_channel->GetDelay ();
+
+  /* 
+   * For now, this device is up whenever a channel is attached to it.
+   */
+  NotifyLinkUp ();
+  return true;
+}
+
+void
+CsmaNetDevice::AddQueue (Ptr<Queue> q)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << q << ")");
+
+  m_queue = q;
+}
+
+void
+CsmaNetDevice::Receive (const Packet& packet)
+{
+  NS_LOG_FUNCTION;
+
+  EthernetHeader header (false);
+  EthernetTrailer trailer;
+  Mac48Address broadcast;
+  Mac48Address multicast;
+  Mac48Address destination;
+  Packet p = packet;
+
+  NS_LOG_LOGIC ("UID is " << p.GetUid());
+
+  // Only receive if send side of net device is enabled
+  if (!IsReceiveEnabled())
+    {
+      m_dropTrace (p);
+      return;
+    }
+
+  if (m_encapMode == RAW)
+    {
+      ForwardUp (packet, 0, GetBroadcast ());
+      m_dropTrace (p);
+      return;
+    }
+  p.RemoveTrailer(trailer);
+  trailer.CheckFcs(p);
+  p.RemoveHeader(header);
+
+  NS_LOG_LOGIC ("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 
+//
+  Mac48Address mcDest;
+  uint8_t      mcBuf[6];
+
+  header.GetDestination ().CopyTo (mcBuf);
+  mcBuf[3] &= 0x80;
+  mcBuf[4] = 0;
+  mcBuf[5] = 0;
+  mcDest.CopyFrom (mcBuf);
+
+  multicast = Mac48Address::ConvertFrom (GetMulticast ());
+  broadcast = Mac48Address::ConvertFrom (GetBroadcast ());
+  destination = Mac48Address::ConvertFrom (GetAddress ());
+
+  if ((header.GetDestination () != broadcast) &&
+      (mcDest != multicast) &&
+      (header.GetDestination () != destination))
+    {
+      NS_LOG_LOGIC ("Dropping pkt ");
+      m_dropTrace (p);
+      return;
+    }
+
+  m_rxTrace (p);
+//
+// protocol must be initialized to avoid a compiler warning in the RAW
+// case that breaks the optimized build.
+//
+  uint16_t protocol = 0;
+
+  switch (m_encapMode)
+    {
+    case ETHERNET_V1:
+    case IP_ARP:
+      protocol = header.GetLengthType();
+      break;
+    case LLC: {
+      LlcSnapHeader llc;
+      p.RemoveHeader (llc);
+      protocol = llc.GetType ();
+    } break;
+    case RAW:
+      NS_ASSERT (false);
+      break;
+    }
+  
+  ForwardUp (p, protocol, header.GetSource ());
+  return;
+}
+
+Address
+CsmaNetDevice::MakeMulticastAddress(Ipv4Address multicastGroup) const
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << multicastGroup << ")");
+//
+// First, get the generic multicast address.
+//
+  Address hardwareDestination = GetMulticast ();
+
+  NS_LOG_LOGIC ("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.
+//
+  Mac48Address etherAddr = Mac48Address::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 Mac48Address,
+//
+  etherAddr.CopyFrom (etherBuffer);
+//
+// Implicit conversion (operator Address ()) is defined for Mac48Address, so
+// use it by just returning the EUI-48 address which is automagically converted
+// to an Address.
+//
+  NS_LOG_LOGIC ("multicast address is " << etherAddr);
+
+  return etherAddr;
+}
+
+Ptr<Queue>
+CsmaNetDevice::GetQueue(void) const 
+{ 
+  NS_LOG_FUNCTION;
+  return m_queue;
+}
+
+Ptr<Channel>
+CsmaNetDevice::DoGetChannel(void) const 
+{ 
+  NS_LOG_FUNCTION;
+  return m_channel;
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/csma-net-device.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,472 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise
+ *
+ * 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca
+ * Derived from the p2p net device file
+ */
+
+#ifndef CSMA_NET_DEVICE_H
+#define CSMA_NET_DEVICE_H
+
+#include <string.h>
+#include "ns3/node.h"
+#include "ns3/backoff.h"
+#include "ns3/address.h"
+#include "ns3/net-device.h"
+#include "ns3/callback.h"
+#include "ns3/packet.h"
+#include "ns3/callback-trace-source.h"
+#include "ns3/nstime.h"
+#include "ns3/data-rate.h"
+#include "ns3/ptr.h"
+#include "ns3/random-variable.h"
+#include "ns3/mac48-address.h"
+
+namespace ns3 {
+
+class Queue;
+class CsmaChannel;
+
+/**
+ * \brief hold in a TraceContext the type of trace source from a CsmaNetDevice
+ */
+class CsmaTraceType : public TraceContextElement
+{
+public:
+  enum Type {
+    RX, 
+    DROP
+  };
+  CsmaTraceType (enum Type type);
+  CsmaTraceType ();
+  void Print (std::ostream &os) const;
+  static uint16_t GetUid (void);
+  std::string GetTypeName (void) const;
+  /**
+   * \returns the type of the trace source which generated an event.
+   */
+  enum Type Get (void) const;
+private:
+  enum Type m_type;
+};
+
+/**
+ * \class CsmaNetDevice
+ * \brief A Device for a Csma Network Link.
+ *
+ * The Csma net device class is analogous to layer 1 and 2 of the
+ * TCP stack. The NetDevice takes a raw packet of bytes and creates a
+ * protocol specific packet from them. The Csma net device class
+ * takes this packet and adds and processes the headers/trailers that
+ * are associated with EthernetV1, EthernetV2, RAW or LLC
+ * protocols. The EthernetV1 packet type adds and removes Ethernet
+ * destination and source addresses. The LLC packet type adds and
+ * removes LLC snap headers. The raw packet type does not add or
+ * remove any headers.  Each Csma net device will receive all
+ * packets written to the Csma link. The ProcessHeader function can
+ * be used to filter out the packets such that higher level layers
+ * only receive packets that are addressed to their associated net
+ * devices
+ *
+ */
+class CsmaNetDevice : public NetDevice {
+public:
+
+  /**
+   * Enumeration of the types of packets supported in the class.
+   *
+   */
+enum CsmaEncapsulationMode {
+  ETHERNET_V1, /**< Version one ethernet packet, length field */
+  IP_ARP,      /**< Ethernet packet encapsulates IP/ARP packet */
+  RAW,         /**< Packet that contains no headers */
+  LLC,         /**< LLC packet encapsulation */  
+};
+
+  CsmaNetDevice (Ptr<Node> node);
+  /**
+   * Construct a CsmaNetDevice
+   *
+   * This is the constructor for the CsmaNetDevice.  It takes as a
+   * parameter the Node to which this device is connected.  Ownership of the
+   * Node pointer is not implied and the node must not be deleted.
+   *
+   * \param node the Node to which this device is connected.
+   * \param addr The source MAC address of the net device.
+   * \param pktType the type of encapsulation
+   */
+  CsmaNetDevice (Ptr<Node> node, Mac48Address addr, CsmaEncapsulationMode pktType);
+
+  /**
+   * Construct a CsmaNetDevice
+   *
+   * This is the constructor for the CsmaNetDevice.  It takes as a
+   * parameter the Node to which this device is connected.  Ownership of the
+   * Node pointer is not implied and the node must not be deleted.
+   *
+   * \param node the Node to which this device is connected.
+   * \param addr The source MAC address of the net device.
+   * \param pktType the type of encapsulation
+   * \param sendEnable whether this device is able to send
+   * \param receiveEnable whether this device is able to receive
+   */
+  CsmaNetDevice (Ptr<Node> node, Mac48Address addr,
+                   CsmaEncapsulationMode pktType,
+                   bool sendEnable, bool receiveEnable);
+  /**
+   * Destroy a CsmaNetDevice
+   *
+   * This is the destructor for the CsmaNetDevice.
+   */
+  virtual ~CsmaNetDevice();
+  /**
+   * Set the Data Rate used for transmission of packets.  The data rate is
+   * set in the Attach () method from the corresponding field in the channel
+   * to which the device is attached.  It can be overridden using this method.
+   *
+   * @see Attach ()
+   * \param bps the data rate at which this object operates
+   */
+  void SetDataRate (DataRate bps);
+  /**
+   * Set the inteframe gap used to separate packets.  The interframe gap
+   * defines the minimum space required between packets sent by this device.
+   * It is usually set in the Attach () method based on the speed of light
+   * delay of the channel to which the device is attached.  It can be 
+   * overridden using this method if desired.
+   *
+   * @see Attach ()
+   * \param t the interframe gap time
+   */
+  void SetInterframeGap (Time t);
+  /**
+   * Set the backoff parameters used to determine the wait to retry
+   * transmitting a packet when the channel is busy.
+   *
+   * @see Attach ()
+   * \param slotTime Length of a packet slot (or average packet time)
+   * \param minSlots Minimum number of slots to wait
+   * \param maxSlots Maximum number of slots to wait
+   * \param maxRetries Maximum number of retries before packet is discard
+   * \param ceiling Cap on the exponential function when calculating max slots
+   */
+  void SetBackoffParams (Time slotTime, uint32_t minSlots, uint32_t maxSlots, 
+                        uint32_t maxRetries, uint32_t ceiling);
+  /**
+   * Attach the device to a channel.
+   *
+   * The function Attach is used to add a CsmaNetDevice to a
+   * CsmaChannel.
+   *
+   * @see SetDataRate ()
+   * @see SetInterframeGap ()
+   * \param ch a pointer to the channel to which this object is being attached.
+   */
+  bool Attach (Ptr<CsmaChannel> ch);
+  /**
+   * Attach a queue to the CsmaNetDevice.
+   *
+   * The CsmaNetDevice "owns" a queue.  This queue is created by the
+   * CsmaTopology object and implements a queueing method such as
+   * DropTail or RED.  The CsmaNetDevice assumes ownership of this
+   * queue and must delete it when the device is destroyed.
+   *
+   * @see CsmaTopology::AddCsmaLink ()
+   * @see Queue
+   * @see DropTailQueue
+   * \param queue a pointer to the queue for which object is assuming
+   *        ownership.
+   */
+  void AddQueue (Ptr<Queue> queue);
+  /**
+   * Receive a packet from a connected CsmaChannel.
+   *
+   * The CsmaNetDevice receives packets from its connected channel
+   * and forwards them up the protocol stack.  This is the public method
+   * used by the channel to indicate that the last bit of a packet has 
+   * arrived at the device.
+   *
+   * @see CsmaChannel
+   * \param p a reference to the received packet
+   */
+  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 Mac48Address
+   * @see Address
+   */
+  Address MakeMulticastAddress (Ipv4Address multicastGroup) const;
+
+  bool IsSendEnabled (void);
+  bool IsReceiveEnabled (void);
+
+  void SetSendEnable (bool);
+  void SetReceiveEnable (bool);
+
+protected:
+  virtual bool DoNeedsArp (void) const;
+  virtual void DoDispose (void);
+  /**
+   * Create a Trace Resolver for events in the net device.
+   * (NOT TESTED)
+   * @see class TraceResolver
+   */
+  virtual Ptr<TraceResolver> GetTraceResolver (void) const;
+
+  /**
+   * Get a copy of the attached Queue.
+   *
+   * This method is provided for any derived class that may need to get
+   * direct access to the underlying queue.
+   *
+   * \return a pointer to the queue.
+   */
+  Ptr<Queue> GetQueue (void) const; 
+  /**
+   * Get a copy of the attached Channel
+   *
+   * This method is provided for any derived class that may need to get
+   * direct access to the connected channel
+   *
+   * \return a pointer to the channel
+   */
+  virtual Ptr<Channel> DoGetChannel (void) const;
+  /**
+   * Adds the necessary headers and trailers to a packet of data in order to
+   * respect the packet type
+   *
+   * \param p Packet to which header should be added
+   * \param dest MAC destination address to which packet should be sent
+   * \param protocolNumber In some protocols, identifies the type of
+   * payload contained in this packet.
+   */
+  void AddHeader (Packet& p, Mac48Address dest, 
+                  uint16_t protocolNumber);
+  /**
+   * Removes, from a packet of data, all headers and trailers that
+   * relate to the packet type
+   *
+   * \param p Packet whose headers need to be processed
+   * \param param An integer parameter that can be set by the function
+   * to return information gathered in the header
+   * \return Returns true if the packet should be forwarded up the
+   * protocol stack.
+   */
+  bool ProcessHeader (Packet& p, uint16_t & param);
+
+private:
+  // disable copy constructor and operator =
+  CsmaNetDevice &operator = (const CsmaNetDevice &o);
+  CsmaNetDevice (const CsmaNetDevice &o);
+  /**
+   * Initializes variablea when construction object.
+   */
+  void Init (bool sendEnable, bool receiveEnable);
+  /**
+   * Send a Packet on the Csma network
+   *
+   * This method does not use a destination address since all packets
+   * are broadcast to all NetDevices attached to the channel. Packet
+   * should contain all needed headers at this time.
+   *
+   * If the device is ready to transmit, the next packet is read off
+   * of the queue and stored locally until it has been transmitted.
+   *
+   * \param p a reference to the packet to send
+   * \param dest destination address
+   * \param protocolNumber -- this parameter is not used here
+   * \return true if success, false on failure
+   */
+  virtual bool SendTo (const Packet& p, const Address& dest, uint16_t protocolNumber);
+
+  /**
+   * Start Sending a Packet Down the Wire.
+   *
+   * The TransmitStart method is the method that is used internally in
+   * the CsmaNetDevice to begin the process of sending a packet
+   * out on the channel.  The corresponding method is called on the
+   * channel to let it know that the physical device this class
+   * represents has virually started sending signals, this causes the
+   * channel to become busy.  An event is scheduled for the time at
+   * which the bits have been completely transmitted. If the channel
+   * is busy, the method reschedules itself for a later time (within
+   * the backoff period)
+   *
+   * @see CsmaChannel::TransmitStart ()
+   * @see TransmitCompleteEvent ()
+   */
+  void TransmitStart ();
+  /**
+   * Stop Sending a Packet Down the Wire and Begin the Interframe Gap.
+   *
+   * The TransmitCompleteEvent method is used internally to finish the process
+   * of sending a packet out on the channel.  During execution of this method
+   * the TransmitEnd method is called on the channel to let it know that the
+   * physical device this class represents has virually finished sending 
+   * signals.  The channel uses this event to begin its speed of light delay
+   * timer after which it notifies the Net Device at the other end of the 
+   * link that the bits have arrived.  During this method, the net device 
+   * also schedules the TransmitReadyEvent at which time the transmitter 
+   * becomes ready to send the next packet.
+   *
+   * @see CsmaChannel::TransmitEnd ()
+   * @see TransmitReadyEvent ()
+   */
+  void TransmitCompleteEvent (void);
+  /**
+   * Cause the Transmitter to Become Ready to Send Another Packet.
+   *
+   * The TransmitReadyEvent method is used internally to re-enable the 
+   * transmit machine of the net device.  It is scheduled after a suitable
+   * interframe gap after the completion of the previous transmission.
+   * The queue is checked at this time, and if there is a packet waiting on
+   * the queue, the transmission process is begun.
+   *
+   * If a packet is in the queue, it is extracted for the queue as the
+   * next packet to be transmitted by the net device.
+   *
+   * @see TransmitStart ()
+   */
+  void TransmitReadyEvent (void);
+
+  /**
+   * Aborts the transmission of the current packet
+   *
+   * If the net device has tried to transmit a packet for more times
+   * than the maximum allowed number of retries (channel always busy)
+   * then the packet is dropped.
+   *
+   */
+  void TransmitAbort (void);
+
+  /** 
+   * Device ID returned by the attached functions. It is used by the
+   * mp-channel to identify each net device to make sure that only
+   * active net devices are writing to the channel
+   */
+  uint32_t m_deviceId; 
+
+  /**
+   * Enable net device to send packets. True by default
+   */
+  bool m_sendEnable;
+  /**
+   * Enable net device to receive packets. True by default
+   */
+  bool m_receiveEnable;
+  /**
+   * Enumeration of the states of the transmit machine of the net device.
+   */
+  enum TxMachineState
+    {
+      READY, /**< The transmitter is ready to begin transmission of a packet */
+      BUSY,  /**< The transmitter is busy transmitting a packet */
+      GAP,    /**< The transmitter is in the interframe gap time */
+      BACKOFF    /**< The transmitter is waiting for the channel to be free */
+    };
+  /**
+   * The state of the Net Device transmit state machine.
+   * @see TxMachineState
+   */
+  TxMachineState m_txMachineState;
+  
+  /**
+   * The type of packet that should be created by the AddHeader
+   * function and that should be processed by the ProcessHeader
+   * function.
+   */
+  CsmaEncapsulationMode m_encapMode;
+  /**
+   * The data rate that the Net Device uses to simulate packet transmission
+   * timing.
+   * @see class DataRate
+   */
+  DataRate m_bps;
+  /**
+   * The interframe gap that the Net Device uses to throttle packet
+   * transmission
+   * @see class Time
+   */
+  Time m_tInterframeGap;
+  /**
+   * Holds the backoff parameters and is used to calculate the next
+   * backoff time to use when the channel is busy and the net device
+   * is ready to transmit
+   */
+  Backoff m_backoff;
+  /**
+   * Next packet that will be transmitted (if transmitter is not
+   * currently transmitting) or packet that is currently being
+   * transmitted.
+   */
+  Packet m_currentPkt;
+  /**
+   * The CsmaChannel to which this CsmaNetDevice has been
+   * attached.
+   * @see class CsmaChannel
+   */
+  Ptr<CsmaChannel> m_channel;
+  /**
+   * The Queue which this CsmaNetDevice uses as a packet source.
+   * Management of this Queue has been delegated to the CsmaNetDevice
+   * and it has the responsibility for deletion.
+   * @see class Queue
+   * @see class DropTailQueue
+   */
+  Ptr<Queue> m_queue;
+  /**
+   * NOT TESTED
+   * The trace source for the packet reception events that the device can
+   * fire.
+   *
+   * @see class CallBackTraceSource
+   * @see class TraceResolver
+   */
+  CallbackTraceSource<const Packet &> m_rxTrace;
+  CallbackTraceSource<const Packet &> m_dropTrace;
+
+};
+
+}; // namespace ns3
+
+#endif // CSMA_NET_DEVICE_H
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/csma-topology.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,102 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+//
+// Copyright (c) 2007 Emmanuelle Laprise
+//
+// 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+//
+
+//
+// Topology helper for Csma channels in ns3.
+
+#include "ns3/assert.h"
+#include "ns3/queue.h"
+
+#include "csma-channel.h"
+#include "csma-net-device.h"
+#include "csma-topology.h"
+#include "ns3/socket-factory.h"
+
+namespace ns3 {
+
+Ptr<CsmaChannel>
+CsmaTopology::CreateCsmaChannel(
+  const DataRate& bps,
+  const Time& delay)
+{
+  Ptr<CsmaChannel> channel = Create<CsmaChannel> (bps, delay);
+
+  return channel;
+}
+
+#if 0
+Ptr<CsmaNetDevice>
+CsmaTopology::AddCsmaEthernetNode(
+  Ptr<Node> n1,
+  Ptr<CsmaChannel> ch,
+  MacAddress addr)
+{
+  Ptr<CsmaNetDevice> nd1 = Create<CsmaNetDevice> (n1, addr, 
+                                                      ns3::CsmaNetDevice::ETHERNET_V1);
+
+  Ptr<Queue> q = Queue::CreateDefault ();
+  nd1->AddQueue(q);
+  nd1->Attach (ch);
+  
+  return nd1;
+}
+
+Ptr<PacketSocket>
+CsmaTopology::ConnectPacketSocket(Ptr<PacketSocketApp> app, 
+                                        Ptr<CsmaNetDevice> ndSrc,
+                                        Ptr<CsmaNetDevice> ndDest)
+{
+  Ptr<PacketSocket> socket = Create<PacketSocket> ();
+  socket->Bind(ndSrc);
+  socket->Connect(ndDest->GetAddress());
+  app->Connect(socket);
+
+  return socket;
+}
+
+Ptr<PacketSocket>
+CsmaTopology::ConnectPacketSocket(Ptr<PacketSocketApp> app,
+                                        Ptr<CsmaNetDevice> ndSrc,
+                                        MacAddress macAddr)
+{
+  Ptr<PacketSocket> socket = Create<PacketSocket> ();
+  socket->Bind(ndSrc);
+  socket->Connect(macAddr);
+  app->Connect(socket);
+
+  return socket;
+}
+
+Ptr<Socket>
+CsmaTopology::CreatePacketSocket(Ptr<Node> n1, std::string iid_name)
+{
+  InterfaceId iid = InterfaceId::LookupByName (iid_name);
+
+  Ptr<SocketFactory> socketFactory =
+    n1->QueryInterface<SocketFactory> (iid);
+
+  Ptr<Socket> socket = socketFactory->CreateSocket ();
+
+  return socket;
+}
+#endif
+
+} // namespace ns3
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/csma-topology.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,123 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+//
+// Copyright (c) 2007 Emmanuelle Laprise
+//
+// 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+//
+// Topology helper for multipoint channels in ns3.
+// 
+#ifndef CSMA_TOPOLOGY_H
+#define CSMA_TOPOLOGY_H
+
+#include "ns3/ptr.h"
+#include "ns3/csma-net-device.h"
+#include "ns3/node.h"
+
+// The topology class consists of only static methods thar are used to
+// create the topology and data flows for an ns3 simulation
+
+namespace ns3 {
+
+class CsmaChannel;
+class Node;
+class DataRate;
+class Queue;
+
+/**
+ * \brief A helper class to create Csma Topologies 
+ *
+ * Csma topologies are created based on the
+ * ns3::CsmaNetDevice subclasses and ns3::CsmaChannel
+ * objects.  This class uses the EthernetNetDevice and
+ * PacketSocket classes in order to create logical connections between
+ * net devices. The PacketSocket class generates the data and the
+ * EthernetNetDevice class creates ethernet packets from the
+ * data, filling in source and destination addresses. The
+ * EthernetNetDevice class filters received data packets
+ * according to its destination Mac addresses.
+ */
+class CsmaTopology {
+public:
+  /** 
+   * \param dataRate Maximum transmission link rate 
+   * \param delay propagation delay between any two nodes 
+   * \return Pointer to the created CsmaChannel
+   * 
+   * Create a CsmaChannel. All nodes connected to a multipoint
+   * channels will receive all packets written to that channel
+   */
+  static Ptr<CsmaChannel> CreateCsmaChannel(
+    const DataRate& dataRate, const Time& delay);
+
+#if 0
+  /**
+   * \param n1 Node to be attached to the multipoint channel
+   * \param ch CsmaChannel to which node n1 should be attached 
+   * \param addr MacAddress that should be assigned to the
+   * EthernetNetDevice that will be added to the node.
+   *
+   * Add a multipoint node to a multipoint channel
+   */
+  static Ptr<CsmaNetDevice> AddCsmaEthernetNode(Ptr<Node> n1, 
+                                                    Ptr<CsmaChannel> ch,
+                                                    MacAddress addr);
+
+  /**
+   * \param app Application that will be sending data to the agent
+   * \param ndSrc Net Device that will be sending the packets onto the
+   * network
+   * \param ndDest Net Device to which ndSrc will be sending the packets
+   * \return A pointer to the PacketSocket
+   *
+   * Creates an PacketSocket and configure it to send packets between
+   * two net devices
+   */
+static Ptr<PacketSocket> ConnectPacketSocket(Ptr<PacketSocketApp> app,
+                                      Ptr<CsmaNetDevice> ndSrc,
+                                      Ptr<CsmaNetDevice> ndDest);
+
+  /**
+   * \param app Application that will be sending data to the agent
+   * \param ndSrc Net Device that will be sending the packets onto the
+   * network 
+   * \param macAddr Mac destination address for the packets send by
+   * the ndSrc net device \return a Pointer to the created
+   * PacketSocket
+   *
+   * Creates an PacketSocket and configure it to send packets from a
+   * net device to a destination MacAddress
+   */
+static Ptr<PacketSocket> ConnectPacketSocket(Ptr<PacketSocketApp> app,
+                                      Ptr<CsmaNetDevice> ndSrc,
+                                      MacAddress macAddr);
+
+  /**
+   * \param n1 Node from which socketfactory should be tested.
+   * \param iid_name Interface identifier ("Packet", in this case)
+   *
+   * This is a test function to make sure that a socket can be created
+   * by using the socketfactory interface provided in the
+   * netdevicenode.
+   */
+static  Ptr<Socket> CreatePacketSocket(Ptr<Node> n1, 
+                                       std::string iid_name);
+#endif
+
+};
+} // namespace ns3
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/waf	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,1 @@
+exec "`dirname "$0"`"/../../../waf "$@"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/wscript	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,19 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def build(bld):
+    obj = bld.create_ns3_module('csma', ['node'])
+    obj.source = [
+        'backoff.cc',
+        'csma-net-device.cc',
+        'csma-channel.cc',
+        'csma-topology.cc',
+        'csma-ipv4-topology.cc',
+        ]
+    headers = bld.create_obj('ns3header')
+    headers.source = [
+        'backoff.h',
+        'csma-net-device.h',
+        'csma-channel.h',
+        'csma-topology.h',
+        'csma-ipv4-topology.h',
+        ]
--- a/src/devices/p2p/p2p-channel.cc	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,192 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 University of Washington
- * 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
- * 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: Craig Dowell <craigdo@ee.washington.edu>
- */
-
-#include "p2p-channel.h"
-#include "p2p-net-device.h"
-#include "ns3/packet.h"
-#include "ns3/simulator.h"
-#include "ns3/debug.h"
-
-NS_DEBUG_COMPONENT_DEFINE ("PointToPointChannel");
-
-namespace ns3 {
-
-//
-// By default, you get a channel with the name "PointToPoint Channel" that 
-// has an "infitely" fast transmission speed and zero delay.
-PointToPointChannel::PointToPointChannel()
-: 
-  Channel ("PointToPoint Channel"), 
-  m_bps (DataRate(0xffffffff)),
-  m_delay (Seconds(0)),
-  m_nDevices(0)
-{
-  NS_DEBUG("PointToPointChannel::PointToPointChannel ()");
-}
-
-PointToPointChannel::PointToPointChannel(
-  const DataRate& bps, 
-  const Time& delay)
-: 
-  Channel ("PointToPoint Channel"), 
-  m_bps (bps),
-  m_delay (delay),
-  m_nDevices(0)
-{
-  NS_DEBUG("PointToPointChannel::PointToPointChannel (" << Channel::GetName() 
-    << ", " << bps.GetBitRate() << ", " << delay << ")");
-}
-
-PointToPointChannel::PointToPointChannel(
-  const std::string& name,
-  const DataRate& bps, 
-  const Time& delay)
-: 
-  Channel (name),
-  m_bps (bps), 
-  m_delay (delay),
-  m_nDevices(0)
-{
-  NS_DEBUG("PointToPointChannel::PointToPointChannel (" << name << ", " << 
-    bps.GetBitRate() << ", " << delay << ")");
-}
-
-  void
-PointToPointChannel::Attach(Ptr<PointToPointNetDevice> device)
-{
-  NS_DEBUG("PointToPointChannel::Attach (" << device << ")");
-  NS_ASSERT(m_nDevices < N_DEVICES && "Only two devices permitted");
-  NS_ASSERT(device != 0);
-
-  m_link[m_nDevices].m_src = device;
-  ++m_nDevices;
-//
-// If we have both devices connected to the channel, then finish introducing
-// the two halves and set the links to IDLE.
-//
-  if (m_nDevices == N_DEVICES)
-    {
-      m_link[0].m_dst = m_link[1].m_src;
-      m_link[1].m_dst = m_link[0].m_src;
-      m_link[0].m_state = IDLE;
-      m_link[1].m_state = IDLE;
-    }
-}
-
-bool
-PointToPointChannel::TransmitStart(Packet& p, Ptr<PointToPointNetDevice> src)
-{
-  NS_DEBUG ("PointToPointChannel::TransmitStart (" << &p << ", " << src << 
-            ")");
-  NS_DEBUG ("PointToPointChannel::TransmitStart (): UID is " << 
-            p.GetUid () << ")");
-
-  NS_ASSERT(m_link[0].m_state != INITIALIZING);
-  NS_ASSERT(m_link[1].m_state != INITIALIZING);
-
-  uint32_t wire = src == m_link[0].m_src ? 0 : 1;
-
-  if (m_link[wire].m_state == TRANSMITTING)
-    {
-      NS_DEBUG("PointToPointChannel::TransmitStart (): **** ERROR ****");
-      NS_DEBUG("PointToPointChannel::TransmitStart (): state TRANSMITTING");
-      return false;
-    }
-
-  NS_DEBUG("PointToPointChannel::TransmitStart (): switch to TRANSMITTING");
-  m_link[wire].m_state = TRANSMITTING;
-  return true;
-}
-
-bool
-PointToPointChannel::TransmitEnd(Packet& p, Ptr<PointToPointNetDevice> src)
-{
-  NS_DEBUG("PointToPointChannel::TransmitEnd (" << &p << ", " << src << ")");
-  NS_DEBUG ("PointToPointChannel::TransmitEnd (): UID is " << 
-            p.GetUid () << ")");
-
-  NS_ASSERT(m_link[0].m_state != INITIALIZING);
-  NS_ASSERT(m_link[1].m_state != INITIALIZING);
-
-  uint32_t wire = src == m_link[0].m_src ? 0 : 1;
-
-  NS_ASSERT(m_link[wire].m_state == TRANSMITTING);
-
-  m_link[wire].m_state = PROPAGATING;
-//
-// The sender is going to free the packet as soon as it has been transmitted.
-// We need to copy it to get a reference so it won't e deleted.
-//
-  Packet packet = p;
-  NS_DEBUG ("PointToPointChannel::TransmitEnd (): Schedule event in " << 
-            m_delay.GetSeconds () << "sec");
-  Simulator::Schedule (m_delay,
-                       &PointToPointChannel::PropagationCompleteEvent,
-                       this, packet, src);
-  return true;
-}
-
-void
-PointToPointChannel::PropagationCompleteEvent(
-  Packet p, 
-  Ptr<PointToPointNetDevice> src)
-{
-  NS_DEBUG("PointToPointChannel::PropagationCompleteEvent (" << &p << ", " << 
-    src << ")");
-  NS_DEBUG ("PointToPointChannel::PropagationCompleteEvent (): UID is " << 
-    p.GetUid () << ")");
-
-  uint32_t wire = src == m_link[0].m_src ? 0 : 1;
-  NS_ASSERT(m_link[wire].m_state == PROPAGATING);
-  m_link[wire].m_state = IDLE;
-
-  NS_DEBUG ("PointToPointChannel::PropagationCompleteEvent (): Receive");
-  m_link[wire].m_dst->Receive (p);
-}
-
-
-uint32_t 
-PointToPointChannel::GetNDevices (void) const
-{
-  return m_nDevices;
-}
-
-Ptr<NetDevice>
-PointToPointChannel::GetDevice (uint32_t i) const
-{
-  NS_ASSERT(i < 2);
-  return m_link[i].m_src;
-}
-
-  DataRate
-PointToPointChannel::GetDataRate (void)
-{
-  return m_bps;
-}
-
-  Time
-PointToPointChannel::GetDelay (void)
-{
-  return m_delay;
-}
-
-
-} // namespace ns3
--- a/src/devices/p2p/p2p-channel.h	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,130 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 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
- */
-
-#ifndef POINT_TO_POINT_CHANNEL_H
-#define POINT_TO_POINT_CHANNEL_H
-
-#include <list>
-#include "ns3/channel.h"
-#include "ns3/ptr.h"
-#include "ns3/packet.h"
-#include "ns3/nstime.h"
-#include "ns3/data-rate.h"
-
-namespace ns3 {
-
-class PointToPointNetDevice;
-
-/**
- * \brief Simple Point To Point Channel.
- *
- * This class represents a very simple point to point channel.  Think full
- * duplex RS-232 or RS-422 with null modem and no handshaking.  There is no
- * multi-drop capability on this channel -- there can be a maximum of two 
- * point-to-point net devices connected.  Once we start talking about multi-
- * drop, or CSMA, or some other sharing mechanism, things begin getting 
- * complicated quickly.  Rather than invent some ad-hoc mechanism, we just
- * Keep It Simple everywhere.
- *
- * When the channel is instaniated, the constructor takes parameters for
- * a single speed, in bits per second, and a speed-of-light delay time as a
- * Time object.  Both directions use the same speed and delay time.
- *
- * There are two "wires" in the channel.  The first device connected gets the
- * [0] wire to transmit on.  The second device gets the [1] wire.  There is a
- * state (IDLE, TRANSMITTING) associated with each wire.
- */
-class PointToPointChannel : public Channel {
-public:
-//
-// This is really kidding myself, since just setting N_DEVICES to 3 isn't
-// going to come close to magically creating a multi-drop link, but I can't
-// bring myself to just type 2 in the code (even though I type 0 and 1 :-).
-//
-  static const int N_DEVICES = 2;
-  /**
-   * \brief Create a PointToPointChannel
-   *
-   * By default, you get a channel with the name "PointToPoint Channel" that
-   * has an "infitely" fast transmission speed and zero delay.
-   */
-  PointToPointChannel ();
-  
-  /**
-   * \brief Create a PointToPointChannel
-   *
-   * \param bps The bitrate of the channel
-   * \param delay Transmission delay through the channel
-   */  
-  PointToPointChannel (const DataRate& bps, const Time& delay);
-  
-  /**
-   * \brief Create a PointToPointChannel
-   *
-   * \param name the name of the channel for identification purposes
-   * \param bps The bitrate of the channel
-   * \param delay Transmission delay through the channel
-   */
-  PointToPointChannel (const std::string& name,
-                 const DataRate& bps, const Time& delay);
-
-  /**
-   * \brief Attach a given netdevice to this channel
-   * \param device pointer to the netdevice to attach to the channel
-   */
-  void Attach (Ptr<PointToPointNetDevice> device);
-  bool TransmitStart (Packet& p, Ptr<PointToPointNetDevice> src);
-  bool TransmitEnd (Packet &p, Ptr<PointToPointNetDevice> src);
-  void PropagationCompleteEvent(Packet p, Ptr<PointToPointNetDevice> src);
-
-
-  virtual uint32_t GetNDevices (void) const;
-  virtual Ptr<NetDevice> GetDevice (uint32_t i) const;
-
-  virtual DataRate GetDataRate (void);
-  virtual Time GetDelay (void);
-
-private:
-  DataRate      m_bps;
-  Time          m_delay;
-
-  int32_t       m_nDevices;
-
-  enum WireState
-    {
-      INITIALIZING,
-      IDLE,
-      TRANSMITTING,
-      PROPAGATING
-    };
-
-  class Link
-  {
-  public:
-    Link() : m_state (INITIALIZING), m_src (0), m_dst (0) {}
-    WireState              m_state;
-    Ptr<PointToPointNetDevice> m_src;
-    Ptr<PointToPointNetDevice> m_dst;
-  };
-    
-  Link    m_link[N_DEVICES];
-};
-
-} // namespace ns3
-
-#endif /* POINT_TO_POINT_CHANNEL_H */
--- a/src/devices/p2p/p2p-net-device.cc	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,354 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2005,2006 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
- * 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 <iostream>
-#include <cassert>
-#include "ns3/debug.h"
-#include "ns3/queue.h"
-#include "ns3/simulator.h"
-#include "ns3/composite-trace-resolver.h"
-#include "p2p-net-device.h"
-#include "p2p-channel.h"
-
-NS_DEBUG_COMPONENT_DEFINE ("PointToPointNetDevice");
-
-namespace ns3 {
-
-PointToPointNetDevice::PointToPointNetDevice (Ptr<Node> node) 
-: 
-  NetDevice(node, MacAddress ("00:00:00:00:00:00")), 
-  m_txMachineState (READY),
-  m_bps (DataRate (0xffffffff)),
-  m_tInterframeGap (Seconds(0)),
-  m_channel (0), 
-  m_queue (0),
-  m_rxTrace ()
-{
-  NS_DEBUG ("PointToPointNetDevice::PointToPointNetDevice (" << node << ")");
-
-  // BUGBUG FIXME
-  //
-  // You _must_ support broadcast to get any sort of packet from the ARP layer.
-  EnableBroadcast (MacAddress ("ff:ff:ff:ff:ff:ff"));
-  EnableMulticast();
-  EnablePointToPoint();
-}
-
-PointToPointNetDevice::~PointToPointNetDevice()
-{
-  NS_DEBUG ("PointToPointNetDevice::~PointToPointNetDevice ()");
-  m_queue = 0;
-}
-
-//
-// Copy constructor for PointToPointNetDevice.
-//
-// We use the underlying NetDevice copy constructor to get the base class
-// copied.  These just remain as is (e.g. you get the same name, the same
-// MAC address).  If you need to fix them up, YOU, the copier need to do 
-// that.
-// 
-// The things we need to be careful of are the channel, the queue and the
-// trace callback.  If the channel pointer is non-zero, we copy the pointer 
-// and add a reference.  If the queue is non-zero, we copy it using the queue
-// assignment operator.  We don't mess with the trace -- we just reset it.
-// We're assuming that the tracing will be set up after the topology creation
-// phase and this won't actually matter.
-//
-PointToPointNetDevice::PointToPointNetDevice (const PointToPointNetDevice& nd)
-: 
-  NetDevice(nd), 
-  m_txMachineState(READY),
-  m_bps (nd.m_bps),
-  m_tInterframeGap (nd.m_tInterframeGap),
-  m_channel(nd.m_channel), 
-  m_queue(0),
-  m_rxTrace ()
-{
-  NS_DEBUG ("PointToPointNetDevice::PointToPointNetDevice (" << &nd << ")");
-
-  if (nd.m_queue)
-    {
-      m_queue = nd.m_queue;
-    }
-    
-}
-
-void PointToPointNetDevice::DoDispose()
-{
-  m_channel = 0;
-  NetDevice::DoDispose ();
-}
-
-//
-// Assignment operator for PointToPointNetDevice.
-//
-// This uses the non-obvious trick of taking the source net device passed by
-// value instead of by reference.  This causes the copy constructor to be
-// invoked (where the real work is done -- see above).  All we have to do
-// here is to return the newly constructed net device.
-//
-  PointToPointNetDevice&
-PointToPointNetDevice::operator= (const PointToPointNetDevice nd)
-{
-  NS_DEBUG ("PointToPointNetDevice::operator= (" << &nd << ")");
-  return *this;
-}
-
-  void 
-PointToPointNetDevice::SetDataRate(DataRate bps)
-{
-  m_bps = bps;
-}
-
-  void 
-PointToPointNetDevice::SetInterframeGap(Time t)
-{
-  m_tInterframeGap = t;
-}
-
-  bool
-PointToPointNetDevice::SendTo (Packet& p, const MacAddress& dest)
-{
-  NS_DEBUG ("PointToPointNetDevice::SendTo (" << &p << ", " << &dest << ")");
-  NS_DEBUG ("PointToPointNetDevice::SendTo (): UID is " << p.GetUid () << ")");
-
-  NS_ASSERT (IsLinkUp ());
-
-#ifdef NOTYET
-    struct NetDevicePacketDestAddress tag;
-    tag.address = address;
-    p.AddTag (tag);
-#endif
-
-//
-// This class simulates a point to point device.  In the case of a serial
-// link, this means that we're simulating something like a UART.  This is
-// not a requirement for a point-to-point link, but it's a typical model for
-// the device.  
-//
-// Generally, a real device will have a list of pending packets to transmit.  
-// An on-device CPU frees the main CPU(s) of the details of what is happening
-// in the device and feeds the USART.  The main CPU basically just sees the 
-// list of packets -- it puts packets into the list, and the device frees the
-// packets when they are transmitted.
-//
-// In the case of our virtual device here, the queue pointed to by m_queue
-// corresponds to this list.  The main CPU adds packets to the list by 
-// calling this method and when the device completes a send, the packets are
-// freed in an "interrupt" service routine.
-//
-// We're going to do the same thing here.  So first of all, the incoming packet
-// goes onto our queue if possible.  If the queue can't handle it, there's
-// nothing to be done.
-//
-    if (m_queue->Enqueue(p) == false )
-      {
-        return false;
-      }
-//
-// If there's a transmission in progress, the "interrupt" will keep the
-// transmission process going.  If the device is idle, we need to start a
-// transmission.
-//
-// In the real world, the USART runs until it finishes sending bits, and then
-// pulls on the device's transmit complete interrupt wire.  At the same time,
-// the electrons from the last wiggle of the wire are busy propagating down
-// the wire.  In the case of a long speed-of-light delay in the wire, we could
-// conceivably start transmitting the next packet before the end of the 
-// previously sent data has even reached the end of the wire.  This situation
-// is usually avoided (like the plague) and an "interframe gap" is introduced.
-// This is usually the round-trip delay on the channel plus some hard-to-
-// quantify receiver turn-around time (the time required for the receiver
-// to process the last frame and prepare for reception of the next).
-//
-// So, if the transmit machine is ready, we need to schedule a transmit 
-// complete event (at which time we tell the channel we're no longer sending
-// bits).  A separate transmit ready event (at which time the transmitter 
-// becomes ready to start sending bits again is scheduled there).  Finally, 
-// we tell the channel (via TransmitStart ()) that we've started wiggling the 
-// wire and bits are coming out.
-//
-// If the transmit machine is not ready, we just leave and the transmit ready
-// event we know is coming will kick-start the transmit process.
-//
-    if (m_txMachineState == READY) 
-      {
-        return TransmitStart (p);
-      }
-    return true;
-}
-
-  bool
-PointToPointNetDevice::TransmitStart (Packet &p)
-{
-  NS_DEBUG ("PointToPointNetDevice::TransmitStart (" << &p << ")");
-  NS_DEBUG (
-    "PointToPointNetDevice::TransmitStart (): UID is " << p.GetUid () << ")");
-//
-// This function is called to start the process of transmitting a packet.
-// We need to tell the channel that we've started wiggling the wire and
-// schedule an event that will be executed when it's time to tell the 
-// channel that we're done wiggling the wire.
-//
-  NS_ASSERT_MSG(m_txMachineState == READY, "Must be READY to transmit");
-  m_txMachineState = BUSY;
-  Time tEvent = Seconds (m_bps.CalculateTxTime(p.GetSize()));
-
-  NS_DEBUG ("PointToPointNetDevice::TransmitStart (): " <<
-    "Schedule TransmitCompleteEvent in " << 
-    tEvent.GetSeconds () << "sec");
-
-  Simulator::Schedule (tEvent, 
-                       &PointToPointNetDevice::TransmitCompleteEvent, 
-                       this);
-  return m_channel->TransmitStart (p, this); 
-}
-
-  void
-PointToPointNetDevice::TransmitCompleteEvent (void)
-{
-  NS_DEBUG ("PointToPointNetDevice::TransmitCompleteEvent ()");
-//
-// This function is called to finish the  process of transmitting a packet.
-// We need to tell the channel that we've stopped wiggling the wire and
-// schedule an event that will be executed when it's time to re-enable
-// the transmitter after the interframe gap.
-//
-  NS_ASSERT_MSG(m_txMachineState == BUSY, "Must be BUSY if transmitting");
-  m_txMachineState = GAP;
-  Packet p;
-  bool found;
-  found = m_queue->Dequeue (p);
-  NS_ASSERT_MSG(found, "Packet must be on queue if transmitted");
-  NS_DEBUG ("PointToPointNetDevice::TransmitCompleteEvent (): Pkt UID is " << 
-            p.GetUid () << ")");
-  m_channel->TransmitEnd (p, this); 
-
-  NS_DEBUG (
-    "PointToPointNetDevice::TransmitCompleteEvent (): " <<
-    "Schedule TransmitReadyEvent in "
-    << m_tInterframeGap.GetSeconds () << "sec");
-
-  Simulator::Schedule (m_tInterframeGap, 
-                       &PointToPointNetDevice::TransmitReadyEvent, 
-                       this);
-}
-
-  void
-PointToPointNetDevice::TransmitReadyEvent (void)
-{
-  NS_DEBUG ("PointToPointNetDevice::TransmitReadyEvent ()");
-//
-// This function is called to enable the transmitter after the interframe
-// gap has passed.  If there are pending transmissions, we use this opportunity
-// to start the next transmit.
-//
-  NS_ASSERT_MSG(m_txMachineState == GAP, "Must be in interframe gap");
-  m_txMachineState = READY;
-
-  if (m_queue->IsEmpty())
-    {
-      return;
-    }
-  else
-    {
-      Packet p;
-      bool found;
-      found = m_queue->Peek (p);
-      NS_ASSERT_MSG(found, "IsEmpty false but no Packet on queue?");
-      TransmitStart (p);
-    }
-}
-
-TraceResolver *
-PointToPointNetDevice::DoCreateTraceResolver (TraceContext const &context)
-{
-  CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
-  resolver->Add ("queue", 
-                 MakeCallback (&Queue::CreateTraceResolver, PeekPointer (m_queue)),
-                 PointToPointNetDevice::QUEUE);
-  resolver->Add ("rx",
-                 m_rxTrace,
-                 PointToPointNetDevice::RX);
-  return resolver;
-}
-
-bool
-PointToPointNetDevice::Attach (Ptr<PointToPointChannel> ch)
-{
-  NS_DEBUG ("PointToPointNetDevice::Attach (" << &ch << ")");
-
-  m_channel = ch;
-
-  m_channel->Attach(this);
-  m_bps = m_channel->GetDataRate ();
-  m_tInterframeGap = m_channel->GetDelay ();
-
-  /* 
-   * For now, this device is up whenever a channel is attached to it.
-   * In fact, it should become up only when the second device
-   * is attached to the channel. So, there should be a way for
-   * a PointToPointChannel to notify both of its attached devices
-   * that the channel is 'complete', hence that the devices are
-   * up, hence that they can call NotifyLinkUp. 
-   */
-  NotifyLinkUp ();
-  return true;
-}
-
-void
-PointToPointNetDevice::AddQueue (Ptr<Queue> q)
-{
-  NS_DEBUG ("PointToPointNetDevice::AddQueue (" << q << ")");
-
-  m_queue = q;
-}
-
-void
-PointToPointNetDevice::Receive (Packet& p)
-{
-  // ignore return value for now.
-  NS_DEBUG ("PointToPointNetDevice::Receive (" << &p << ")");
-
-  m_rxTrace (p);
-  ForwardUp (p);
-}
-
-Ptr<Queue>
-PointToPointNetDevice::GetQueue(void) const 
-{ 
-    return m_queue;
-}
-
-Ptr<Channel>
-PointToPointNetDevice::DoGetChannel(void) const 
-{ 
-    return m_channel;
-}
-
-bool 
-PointToPointNetDevice::DoNeedsArp (void) const
-{
-  return false;
-}
-
-} // namespace ns3
--- a/src/devices/p2p/p2p-net-device.h	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,313 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 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: Craig Dowell <craigdo@ee.washington.edu>
- */
-
-#ifndef POINT_TO_POINT_NET_DEVICE_H
-#define POINT_TO_POINT_NET_DEVICE_H
-
-#include <string.h>
-#include "ns3/mac-address.h"
-#include "ns3/node.h"
-#include "ns3/net-device.h"
-#include "ns3/callback.h"
-#include "ns3/packet.h"
-#include "ns3/callback-trace-source.h"
-#include "ns3/nstime.h"
-#include "ns3/data-rate.h"
-#include "ns3/ptr.h"
-
-namespace ns3 {
-
-class Queue;
-class PointToPointChannel;
-
-/**
- * \class PointToPointNetDevice
- * \brief A Device for a Point to Point Network Link.
- *
- * Ns-3 takes a four-layer view of a protocol stack.  This is the same model
- * that TCP uses.  In this view, layers 5-7 of the OSI reference model are
- * grouped together into an application layer; layer four (transport / TCP) is
- * broken out; layer three (network / IP) is broken out; and layers 1-2 are
- * grouped together.  We call this grouping of layers one and two a NetDevice
- * and represent it as a class in the system.
- *
- * The NetDevice class is specialized according to the needs of the specific
- * kind of network link.  In this case, the link is a PointToPoint link.  The
- * PointToPoint link is a family of classes that includes this class, the
- * PointToPointNetDevice, a PointToPointChannel class that represents the 
- * actual medium across which bits are sent, a PointToPointIpv4Interface class
- * that provides the hook to tie a general purpose node to this specific
- * link, and finally, a PointToPointTopology object that is responsible for
- * putting all of the pieces together.
- *
- * This is the PointToPointNetDevice class that represents, essentially, the
- * PC card that is used to connect to the PointToPoint network.
- */
-class PointToPointNetDevice : public NetDevice {
-public:
-  /**
-   * Enumeration of the types of traces supported in the class.
-   *
-   */
-  enum TraceType {
-    QUEUE, /**< Trace queue events on the attached queue */
-    RX,    /**< Trace packet reception events (from the channel) */
-  };
-  /**
-   * Construct a PointToPointNetDevice
-   *
-   * This is the constructor for the PointToPointNetDevice.  It takes as a
-   * parameter the Node to which this device is connected.  Ownership of the
-   * Node pointer is not implied and the node must not be deleded.
-   *
-   * @see PointToPointTopology::AddPointToPointLink ()
-   * @param node the Node to which this device is connected.
-   */
-  PointToPointNetDevice (Ptr<Node> node);
-  /**
-   * Copy Construct a PointToPointNetDevice
-   *
-   * This is the copy constructor for the PointToPointNetDevice.  This is
-   * primarily used in topology creation.
-   *
-   * @see PointToPointTopology::AddPointToPointLink ()
-   * @param nd the object to be copied
-   */
-  PointToPointNetDevice (const PointToPointNetDevice& nd);
-  /**
-   * Destroy a PointToPointNetDevice
-   *
-   * This is the destructor for the PointToPointNetDevice.
-   */
-  virtual ~PointToPointNetDevice();
-  /**
-   * Assignment Operator for a PointToPointNetDevice
-   *
-   * This is the assignment operator for the PointToPointNetDevice.  This is
-   * to allow
-   *
-   * @param nd the object to be copied
-   */
-  PointToPointNetDevice& operator= (PointToPointNetDevice nd);
-  /**
-   * Set the Data Rate used for transmission of packets.  The data rate is
-   * set in the Attach () method from the corresponding field in the channel
-   * to which the device is attached.  It can be overridden using this method.
-   *
-   * @see Attach ()
-   * @param bps the data rate at which this object operates
-   */
-  void SetDataRate(DataRate bps);
-  /**
-   * Set the inteframe gap used to separate packets.  The interframe gap
-   * defines the minimum space required between packets sent by this device.
-   * It is usually set in the Attach () method based on the speed of light
-   * delay of the channel to which the device is attached.  It can be 
-   * overridden using this method if desired.
-   *
-   * @see Attach ()
-   * @param t the interframe gap time
-   */
-  void SetInterframeGap(Time t);
-  /**
-   * Attach the device to a channel.
-   *
-   * The PointToPointTopology object creates a PointToPointChannel and two
-   * PointtoPointNetDevices.  In order to introduce these components to each
-   * other, the topology object calls Attach () on each PointToPointNetDevice.
-   * Inside this method, the Net Device calls out to the PointToPointChannel
-   * to introduce itself.
-   *
-   * @see PointToPointTopology::AddPointToPointLink ()
-   * @see SetDataRate ()
-   * @see SetInterframeGap ()
-   * @param ch a pointer to the channel to which this object is being attached.
-   */
-  bool Attach(Ptr<PointToPointChannel> ch);
-  /**
-   * Attach a queue to the PointToPointNetDevice.
-   *
-   * The PointToPointNetDevice "owns" a queue.  This queue is created by the
-   * PointToPointTopology object and implements a queueing method such as
-   * DropTail or RED.  The PointToPointNetDevice assumes ownership of this
-   * queue and must delete it when the device is destroyed.
-   *
-   * @see PointToPointTopology::AddPointToPointLink ()
-   * @see Queue
-   * @see DropTailQueue
-   * @param queue a pointer to the queue for which object is assuming
-   *        ownership.
-   */
-  void AddQueue(Ptr<Queue> queue);
-  /**
-   * Receive a packet from a connected PointToPointChannel.
-   *
-   * The PointToPointNetDevice receives packets from its connected channel
-   * and forwards them up the protocol stack.  This is the public method
-   * used by the channel to indicate that the last bit of a packet has 
-   * arrived at the device.
-   *
-   * @see PointToPointChannel
-   * @param p a reference to the received packet
-   */
-  void Receive (Packet& p);
-protected:
-  virtual void DoDispose (void);
-  /**
-   * Get a copy of the attached Queue.
-   *
-   * This method is provided for any derived class that may need to get
-   * direct access to the underlying queue.
-   *
-   * @see PointToPointTopology
-   * @returns a pointer to the queue.
-   */
-  Ptr<Queue> GetQueue(void) const; 
-  /**
-   * Get a copy of the attached Channel
-   *
-   * This method is provided for any derived class that may need to get
-   * direct access to the connected channel
-   *
-   * @see PointToPointChannel
-   * @returns a pointer to the channel
-   */
-  virtual Ptr<Channel> DoGetChannel(void) const;
-private:
-  /**
-   * Send a Packet Down the Wire.
-   *
-   * The SendTo method is defined as the standard way that the level three
-   * protocol uses to tell a NetDevice to send a packet.  SendTo is declared
-   * as abstract in the NetDevice class and we declare it here.
-   *
-   * @see NetDevice
-   * @param p a reference to the packet to send
-   * @param dest a reference to the MacAddress of the destination device
-   * @returns true if success, false on failure
-   */
-  virtual bool SendTo (Packet& p, const MacAddress& dest);
-  /**
-   * Start Sending a Packet Down the Wire.
-   *
-   * The TransmitStart method is the method that is used internally in the
-   * PointToPointNetDevice to begin the process of sending a packet out on
-   * the channel.  The corresponding method is called on the channel to let
-   * it know that the physical device this class represents has virually
-   * started sending signals.  An event is scheduled for the time at which
-   * the bits have been completely transmitted.
-   *
-   * @see PointToPointChannel::TransmitStart ()
-   * @see TransmitCompleteEvent ()
-   * @param p a reference to the packet to send
-   * @returns true if success, false on failure
-   */
-  bool TransmitStart (Packet &p);
-  /**
-   * Stop Sending a Packet Down the Wire and Begin the Interframe Gap.
-   *
-   * The TransmitCompleteEvent method is used internally to finish the process
-   * of sending a packet out on the channel.  During execution of this method
-   * the TransmitEnd method is called on the channel to let it know that the
-   * physical device this class represents has virually finished sending 
-   * signals.  The channel uses this event to begin its speed of light delay
-   * timer after which it notifies the Net Device at the other end of the 
-   * link that the bits have arrived.  During this method, the net device 
-   * also schedules the TransmitReadyEvent at which time the transmitter 
-   * becomes ready to send the next packet.
-   *
-   * @see PointToPointChannel::TransmitEnd ()
-   * @see TransmitReadyEvent ()
-   * @returns true if success, false on failure
-   */
-  void TransmitCompleteEvent (void);
-  /**
-   * Cause the Transmitter to Become Ready to Send Another Packet.
-   *
-   * The TransmitReadyEvent method is used internally to re-enable the 
-   * transmit machine of the net device.  It is scheduled after a suitable
-   * interframe gap after the completion of the previous transmission.
-   * The queue is checked at this time, and if there is a packet waiting on
-   * the queue, the transmission process is begun.
-   *
-   * @see TransmitStart ()
-   */
-  void TransmitReadyEvent (void);
-  /**
-   * Create a Trace Resolver for events in the net device.
-   *
-   * @see class TraceResolver
-   */
-  virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context);
-  virtual bool DoNeedsArp (void) const;
-  /**
-   * Enumeration of the states of the transmit machine of the net device.
-   */
-  enum TxMachineState
-    {
-      READY, /**< The transmitter is ready to begin transmission of a packet */
-      BUSY,  /**< The transmitter is busy transmitting a packet */
-      GAP    /**< The transmitter is in the interframe gap time */
-    };
-  /**
-   * The state of the Net Device transmit state machine.
-   * @see TxMachineState
-   */
-  TxMachineState m_txMachineState;
-  /**
-   * The data rate that the Net Device uses to simulate packet transmission
-   * timing.
-   * @see class DataRate
-   */
-  DataRate       m_bps;
-  /**
-   * The interframe gap that the Net Device uses to throttle packet
-   * transmission
-   * @see class Time
-   */
-  Time           m_tInterframeGap;
-  /**
-   * The PointToPointChannel to which this PointToPointNetDevice has been
-   * attached.
-   * @see class PointToPointChannel
-   */
-  Ptr<PointToPointChannel> m_channel;
-  /**
-   * The Queue which this PointToPointNetDevice uses as a packet source.
-   * Management of this Queue has been delegated to the PointToPointNetDevice
-   * and it has the responsibility for deletion.
-   * @see class Queue
-   * @see class DropTailQueue
-   */
-  Ptr<Queue> m_queue;
-  /**
-   * The trace source for the packet reception events that the device can
-   * fire.
-   *
-   * @see class CallBackTraceSource
-   * @see class TraceResolver
-   */
-  CallbackTraceSource<Packet &> m_rxTrace;
-};
-
-}; // namespace ns3
-
-#endif // POINT_TO_POINT_NET_DEVICE_H
-
--- a/src/devices/p2p/p2p-topology.cc	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,172 +0,0 @@
-/* -*- 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
-//
-// Author: George F. Riley<riley@ece.gatech.edu>
-//
-
-//
-// Topology helper for ns3.
-// George F. Riley, Georgia Tech, Spring 2007
-
-#include <algorithm>
-#include "ns3/assert.h"
-#include "ns3/debug.h"
-#include "ns3/fatal-error.h"
-#include "ns3/nstime.h"
-#include "ns3/internet-node.h"
-#include "ns3/ipv4-address.h"
-#include "ns3/ipv4.h"
-#include "ns3/queue.h"
-
-#include "p2p-channel.h"
-#include "p2p-net-device.h"
-#include "p2p-topology.h"
-
-namespace ns3 {
-
-Ptr<PointToPointChannel>
-PointToPointTopology::AddPointToPointLink(
-  Ptr<Node> n1,
-  Ptr<Node> n2,
-  const DataRate& bps,
-  const Time& delay)
-{
-  Ptr<PointToPointChannel> channel = Create<PointToPointChannel> (bps, delay);
-
-  Ptr<PointToPointNetDevice> net1 = Create<PointToPointNetDevice> (n1);
-
-  Ptr<Queue> q = Queue::CreateDefault ();
-  net1->AddQueue(q);
-  net1->Attach (channel);
-  
-  Ptr<PointToPointNetDevice> net2 = Create<PointToPointNetDevice> (n2);
-
-  q = Queue::CreateDefault ();
-  net2->AddQueue(q);
-  net2->Attach (channel);
-
-  return channel;
-}
-
-void
-PointToPointTopology::AddIpv4Addresses(
-  Ptr<const PointToPointChannel> chan,
-  Ptr<Node> n1, const Ipv4Address& addr1,
-  Ptr<Node> n2, const Ipv4Address& addr2)
-{
-
-  // Duplex link is assumed to be subnetted as a /30
-  // May run this unnumbered in the future?
-  Ipv4Mask netmask("255.255.255.252");
-  NS_ASSERT (netmask.IsMatch(addr1,addr2));
-
-  // The PointToPoint channel is used to find the relevant NetDevices
-  NS_ASSERT (chan->GetNDevices () == 2);
-  Ptr<NetDevice> nd1 = chan->GetDevice (0);
-  Ptr<NetDevice> nd2 = chan->GetDevice (1);
-  // Make sure that nd1 belongs to n1 and nd2 to n2
-  if ( (nd1->GetNode ()->GetId () == n2->GetId () ) && 
-       (nd2->GetNode ()->GetId () == n1->GetId () ) )
-    {
-      std::swap(nd1, nd2);
-    }
-  NS_ASSERT (nd1->GetNode ()->GetId () == n1->GetId ());
-  NS_ASSERT (nd2->GetNode ()->GetId () == n2->GetId ());
-  
-  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);
-
-  Ptr<Ipv4> ip2 = n2->QueryInterface<Ipv4> (Ipv4::iid);
-  uint32_t index2 = ip2->AddInterface (nd2);
-
-  ip2->SetAddress (index2, addr2);
-  ip2->SetNetworkMask (index2, netmask);
-  ip2->SetUp (index2);
-  
-}
-
-void
-PointToPointTopology::AddIpv4Routes (
-  Ptr<Node> n1, Ptr<Node> n2, Ptr<const PointToPointChannel> chan)
-{ 
-  // The PointToPoint channel is used to find the relevant NetDevices
-  NS_ASSERT (chan->GetNDevices () == 2);
-  Ptr<NetDevice> nd1 = chan->GetDevice (0);
-  Ptr<NetDevice> nd2 = chan->GetDevice (1);
-
-  // Assert that n1 is the Node owning one of the two NetDevices
-  // and make sure that nd1 corresponds to it
-  if (nd1->GetNode ()->GetId () == n1->GetId ())
-    {
-      ; // Do nothing
-    }
-  else if (nd2->GetNode ()->GetId () == n1->GetId ())
-    {
-      std::swap(nd1, nd2);
-    }
-  else
-    {
-      NS_FATAL_ERROR("P2PTopo: Node does not contain an interface on Channel");
-    }
-
-   // Assert that n2 is the Node owning one of the two NetDevices
-   // and make sure that nd2 corresponds to it
-  if (nd2->GetNode ()->GetId () != n2->GetId ())
-    {
-      NS_FATAL_ERROR("P2PTopo: Node does not contain an interface on Channel");
-    }
-
-  // Assert that both are Ipv4 nodes
-  Ptr<Ipv4> ip1 = nd1->GetNode ()->QueryInterface<Ipv4> (Ipv4::iid);
-  Ptr<Ipv4> ip2 = nd2->GetNode ()->QueryInterface<Ipv4> (Ipv4::iid);
-  NS_ASSERT(ip1 != 0 && ip2 != 0);
-
-  // Get interface indexes for both nodes corresponding to the right channel
-  uint32_t index1 = 0;
-  bool found = false;
-  for (uint32_t i = 0; i < ip1->GetNInterfaces (); i++)
-    {
-      if (ip1 ->GetNetDevice (i) == nd1)
-        {
-          index1 = i;
-          found = true;
-        }
-    }
-  NS_ASSERT(found);
-
-  uint32_t index2 = 0;
-  found = false;
-  for (uint32_t i = 0; i < ip2->GetNInterfaces (); i++)
-    {
-      if (ip2 ->GetNetDevice (i) == nd2)
-        {
-          index2 = i;
-          found = true;
-        }
-    }
-  NS_ASSERT(found);
-
-  ip1->AddHostRouteTo (ip2-> GetAddress (index2), index1);
-  ip2->AddHostRouteTo (ip1-> GetAddress (index1), index2); 
-}
-
-} // namespace ns3
- 
--- a/src/devices/p2p/p2p-topology.h	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,87 +0,0 @@
-/* -*- 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
-//
-// Author: George F. Riley<riley@ece.gatech.edu>
-//
-// Topology helper for ns3.
-// George F. Riley, Georgia Tech, Spring 2007
-#ifndef __POINT_TO_POINT_TOPOLOGY_H__
-#define __POINT_TO_POINT_TOPOLOGY_H__
-
-#include "ns3/ptr.h"
-
-// The topology class consists of only static methods thar are used to
-// create the topology and data flows for an ns3 simulation
-
-namespace ns3 {
-
-class PointToPointChannel;
-class Node;
-class IPAddr;
-class DataRate;
-class Queue;
-
-/**
- * \brief A helper class to create Topologies based on the 
- * ns3::PointToPointNetDevice and  ns3::PointToPointChannel objects.
- */
-class PointToPointTopology {
-public:
-  /** 
-   * \param n1 Node
-   * \param n2 Node
-   * \param dataRate Maximum transmission link rate 
-   * \param delay one-way propagation delay 
-   * \return Pointer to the underlying PointToPointChannel
-   * 
-   * Add a full-duplex point-to-point link between two nodes
-   * and attach PointToPointNetDevices to the resulting
-   * PointToPointChannel.  
-   */
-  static Ptr<PointToPointChannel> AddPointToPointLink(
-    Ptr<Node> n1, Ptr<Node> n2, const DataRate& dataRate, const Time& delay);
-
-  /** 
-   * \param chan PointToPointChannel to use
-   * \param n1 Node
-   * \param addr1 Ipv4 Address for n1
-   * \param n2 Node
-   * \param addr2 Ipv4 Address for n2
-   * 
-   * Add Ipv4Addresses to the Ipv4 interfaces associated with the 
-   * two PointToPointNetDevices on the provided PointToPointChannel
-   */
-  static void AddIpv4Addresses(
-    Ptr<const PointToPointChannel> chan,
-    Ptr<Node> n1, const Ipv4Address& addr1,
-    Ptr<Node> n2, const Ipv4Address& addr2);
-
-  /**
-   * \param channel PointToPointChannel to use
-   * \param n1 Node
-   * \param n2 Node
-   * 
-   * For the given PointToPointChannel, for each Node, add an 
-   * IPv4 host route to the IPv4 address of the peer node.  
-   */
-  static void AddIpv4Routes (Ptr<Node> n1, Ptr<Node> n2, Ptr<const PointToPointChannel> channel);
-};
-
-} // namespace ns3
-
-#endif
-
--- a/src/devices/p2p/wscript	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
-
-
-def configure(conf):
-    conf.env.append_value('NS3_MODULES', 'ns3-p2p')
-
-
-def build(bld):
-    p2p = bld.create_obj('cpp', 'shlib')
-    p2p.name = 'ns3-p2p'
-    p2p.target = p2p.name
-    p2p.uselib_local = ['ns3-node']
-    p2p.source = [
-        'p2p-net-device.cc',
-        'p2p-channel.cc',
-        'p2p-topology.cc',
-        ]
-    headers = bld.create_obj('ns3header')
-    headers.source = [
-        'p2p-net-device.h',
-        'p2p-channel.h',
-        'p2p-topology.h',
-        ]
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/point-to-point/point-to-point-channel.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,149 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 University of Washington
+ * 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
+ * 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: Craig Dowell <craigdo@ee.washington.edu>
+ */
+
+#include "point-to-point-channel.h"
+#include "point-to-point-net-device.h"
+#include "ns3/packet.h"
+#include "ns3/simulator.h"
+#include "ns3/log.h"
+
+NS_LOG_COMPONENT_DEFINE ("PointToPointChannel");
+
+namespace ns3 {
+
+//
+// By default, you get a channel with the name "PointToPoint Channel" that 
+// has an "infitely" fast transmission speed and zero delay.
+PointToPointChannel::PointToPointChannel()
+: 
+  Channel ("PointToPoint Channel"), 
+  m_bps (DataRate(0xffffffff)),
+  m_delay (Seconds(0)),
+  m_nDevices(0)
+{
+  NS_LOG_FUNCTION;
+}
+
+PointToPointChannel::PointToPointChannel(
+  const DataRate& bps, 
+  const Time& delay)
+: 
+  Channel ("PointToPoint Channel"), 
+  m_bps (bps),
+  m_delay (delay),
+  m_nDevices(0)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << Channel::GetName() << ", " << bps.GetBitRate() << 
+    ", " << delay << ")");
+}
+
+PointToPointChannel::PointToPointChannel(
+  const std::string& name,
+  const DataRate& bps, 
+  const Time& delay)
+: 
+  Channel (name),
+  m_bps (bps), 
+  m_delay (delay),
+  m_nDevices(0)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << name << ", " << bps.GetBitRate() << ", " << 
+    delay << ")");
+}
+
+void
+PointToPointChannel::Attach(Ptr<PointToPointNetDevice> device)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << device << ")");
+  NS_ASSERT(m_nDevices < N_DEVICES && "Only two devices permitted");
+  NS_ASSERT(device != 0);
+
+  m_link[m_nDevices++].m_src = device;
+//
+// If we have both devices connected to the channel, then finish introducing
+// the two halves and set the links to IDLE.
+//
+  if (m_nDevices == N_DEVICES)
+    {
+      m_link[0].m_dst = m_link[1].m_src;
+      m_link[1].m_dst = m_link[0].m_src;
+      m_link[0].m_state = IDLE;
+      m_link[1].m_state = IDLE;
+    }
+}
+
+bool
+PointToPointChannel::TransmitStart(Packet& p,
+                                        Ptr<PointToPointNetDevice> src,
+                                        const Time& txTime)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << &p << ", " << src << ")");
+  NS_LOG_LOGIC ("UID is " << p.GetUid () << ")");
+
+  NS_ASSERT(m_link[0].m_state != INITIALIZING);
+  NS_ASSERT(m_link[1].m_state != INITIALIZING);
+
+  uint32_t wire = src == m_link[0].m_src ? 0 : 1;
+
+  // Here we schedule the packet receive event at the receiver,
+  // which simplifies this model quite a bit.  The channel just
+  // adds the propagation delay time
+  Simulator::Schedule (txTime + m_delay,
+                       &PointToPointNetDevice::Receive,
+                       m_link[wire].m_dst, p);
+  return true;
+}
+
+uint32_t 
+PointToPointChannel::GetNDevices (void) const
+{
+  NS_LOG_FUNCTION;
+  return m_nDevices;
+}
+
+Ptr<NetDevice>
+PointToPointChannel::GetDevice (uint32_t i) const
+{
+  NS_LOG_FUNCTION;
+  NS_ASSERT(i < 2);
+  return m_link[i].m_src;
+}
+
+const DataRate&
+PointToPointChannel::GetDataRate (void)
+{
+  NS_LOG_FUNCTION;
+  return m_bps;
+}
+
+const Time&
+PointToPointChannel::GetDelay (void)
+{
+  NS_LOG_FUNCTION;
+  return m_delay;
+}
+
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/point-to-point/point-to-point-channel.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,127 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 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
+ */
+
+#ifndef POINT_TO_POINT_CHANNEL_H
+#define POINT_TO_POINT_CHANNEL_H
+
+#include <list>
+#include "ns3/channel.h"
+#include "ns3/ptr.h"
+#include "ns3/packet.h"
+#include "ns3/nstime.h"
+#include "ns3/data-rate.h"
+
+namespace ns3 {
+
+class PointToPointNetDevice;
+
+/**
+ * \brief Simple Point To Point Channel.
+ *
+ * This class represents a very simple point to point channel.  Think full
+ * duplex RS-232 or RS-422 with null modem and no handshaking.  There is no
+ * multi-drop capability on this channel -- there can be a maximum of two 
+ * point-to-point net devices connected.  Once we start talking about multi-
+ * drop, or CSMA, or some other sharing mechanism, things begin getting 
+ * complicated quickly.  Rather than invent some ad-hoc mechanism, we just
+ * Keep It Simple everywhere.
+ *
+ * When the channel is instaniated, the constructor takes parameters for
+ * a single speed, in bits per second, and a speed-of-light delay time as a
+ * Time object.  Both directions use the same speed and delay time.
+ *
+ * There are two "wires" in the channel.  The first device connected gets the
+ * [0] wire to transmit on.  The second device gets the [1] wire.  There is a
+ * state (IDLE, TRANSMITTING) associated with each wire.
+ */
+class PointToPointChannel : public Channel {
+public:
+// Each point to point link has exactly two net devices
+  static const int N_DEVICES = 2;
+  /**
+   * \brief Create a PointToPointChannel
+   *
+   * By default, you get a channel with the name "PointToPoint Channel" that
+   * has an "infitely" fast transmission speed and zero delay.
+   */
+  PointToPointChannel ();
+  
+  /**
+   * \brief Create a PointToPointChannel
+   *
+   * \param bps The maximum bitrate of the channel
+   * \param delay Transmission delay through the channel
+   */  
+  PointToPointChannel (const DataRate& bps, const Time& delay);
+  
+  /**
+   * \brief Create a PointToPointChannel
+   *
+   * \param name the name of the channel for identification purposes
+   * \param bps The maximum bitrate of the channel
+   * \param delay Transmission delay through the channel
+   */
+  PointToPointChannel (const std::string& name,
+                 const DataRate& bps, const Time& delay);
+
+  /**
+   * \brief Attach a given netdevice to this channel
+   * \param device pointer to the netdevice to attach to the channel
+   */
+  void Attach (Ptr<PointToPointNetDevice> device);
+  bool TransmitStart (Packet& p, Ptr<PointToPointNetDevice> src,
+                      const Time& txTime);
+  // Below two not needed
+  //bool TransmitEnd (Packet &p, Ptr<PointToPointNetDevice> src);
+  //void PropagationCompleteEvent(Packet p, Ptr<PointToPointNetDevice> src);
+
+
+  virtual uint32_t GetNDevices (void) const;
+  virtual Ptr<NetDevice> GetDevice (uint32_t i) const;
+
+  virtual const DataRate& GetDataRate (void);
+  virtual const Time&     GetDelay (void);
+
+private:
+  DataRate      m_bps;
+  Time          m_delay;
+  int32_t       m_nDevices;
+
+  enum WireState
+    {
+      INITIALIZING,
+      IDLE,
+      TRANSMITTING,
+      PROPAGATING
+    };
+
+  class Link
+  {
+  public:
+    Link() : m_state (INITIALIZING), m_src (0), m_dst (0) {}
+    WireState              m_state;
+    Ptr<PointToPointNetDevice> m_src;
+    Ptr<PointToPointNetDevice> m_dst;
+  };
+    
+  Link    m_link[N_DEVICES];
+};
+
+} // namespace ns3
+
+#endif /* POINT_TO_POINT_CHANNEL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/point-to-point/point-to-point-net-device.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,295 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2005,2006 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
+ * 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:  Craig Dowell <craigdo@ee.washington.edu>
+ * Revised: George Riley <riley@ece.gatech.edu>
+ */
+
+#include "ns3/log.h"
+#include "ns3/queue.h"
+#include "ns3/simulator.h"
+#include "ns3/composite-trace-resolver.h"
+#include "ns3/mac48-address.h"
+#include "ns3/llc-snap-header.h"
+#include "point-to-point-net-device.h"
+#include "point-to-point-channel.h"
+
+NS_LOG_COMPONENT_DEFINE ("PointToPointNetDevice");
+
+namespace ns3 {
+
+DataRateDefaultValue PointToPointNetDevice::g_defaultRate(
+           "PointToPointLinkDataRate", 
+           "The default data rate for point to point links",
+           DataRate ("10Mb/s"));
+
+PointToPointTraceType::PointToPointTraceType ()
+{
+  NS_LOG_FUNCTION;
+}
+void 
+PointToPointTraceType::Print (std::ostream &os) const
+{
+  os << "dev-rx";
+}
+
+uint16_t 
+PointToPointTraceType::GetUid (void)
+{
+  NS_LOG_FUNCTION;
+  static uint16_t uid = AllocateUid<PointToPointTraceType> ("PointToPointTraceType");
+  return uid;
+}
+
+std::string 
+PointToPointTraceType::GetTypeName (void) const
+{
+  NS_LOG_FUNCTION;
+  return "ns3::PointToPointTraceType";
+}
+
+
+PointToPointNetDevice::PointToPointNetDevice (Ptr<Node> node,
+                                              const DataRate& rate) 
+: 
+  NetDevice(node, Mac48Address::Allocate ()), 
+  m_txMachineState (READY),
+  m_bps (rate),
+  m_tInterframeGap (Seconds(0)),
+  m_channel (0), 
+  m_queue (0),
+  m_rxTrace ()
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << node << ")");
+//
+// XXX BUGBUG
+//
+// You _must_ support broadcast to get any sort of packet from the ARP layer.
+//
+  EnableBroadcast (Mac48Address ("ff:ff:ff:ff:ff:ff"));
+//
+// We want to allow multicast packets to flow across this link
+//
+  EnableMulticast (Mac48Address ("01:00:5e:00:00:00"));
+  EnablePointToPoint();
+}
+
+PointToPointNetDevice::~PointToPointNetDevice()
+{
+  NS_LOG_FUNCTION;
+  m_queue = 0;
+}
+
+void 
+PointToPointNetDevice::AddHeader(Packet& p, uint16_t protocolNumber)
+{
+  NS_LOG_FUNCTION;
+  LlcSnapHeader llc;
+  llc.SetType (protocolNumber);
+  p.AddHeader (llc);
+}
+
+bool 
+PointToPointNetDevice::ProcessHeader(Packet& p, uint16_t& param)
+{
+  NS_LOG_FUNCTION;
+  LlcSnapHeader llc;
+  p.RemoveHeader (llc);
+
+  param = llc.GetType ();
+
+  return true;
+}
+
+void PointToPointNetDevice::DoDispose()
+{
+  NS_LOG_FUNCTION;
+  m_channel = 0;
+  NetDevice::DoDispose ();
+}
+
+void PointToPointNetDevice::SetDataRate(const DataRate& bps)
+{
+  NS_LOG_FUNCTION;
+  m_bps = bps;
+}
+
+void PointToPointNetDevice::SetInterframeGap(const Time& t)
+{
+  NS_LOG_FUNCTION;
+  m_tInterframeGap = t;
+}
+
+bool PointToPointNetDevice::SendTo (const Packet& packet, const Address& dest, 
+                                    uint16_t protocolNumber)
+{
+  NS_LOG_FUNCTION;
+  Packet p = packet;
+  NS_LOG_LOGIC ("p=" << &p << ", dest=" << &dest);
+  NS_LOG_LOGIC ("UID is " << p.GetUid ());
+
+  // GFR Comment. Why is this an assertion? Can't a link legitimately
+  // "go down" during the simulation?  Shouldn't we just wait for it
+  // to come back up?
+  NS_ASSERT (IsLinkUp ());
+  AddHeader(p, protocolNumber);
+
+//
+// This class simulates a point to point device.  In the case of a serial
+// link, this means that we're simulating something like a UART.
+//
+//
+// If there's a transmission in progress, we enque the packet for later
+// transmission; otherwise we send it now.
+  if (m_txMachineState == READY) 
+    {
+// We still enqueue and dequeue it to hit the tracing hooks
+      m_queue->Enqueue (p);
+      m_queue->Dequeue (p);
+      return TransmitStart (p);
+    }
+  else
+    {
+      return m_queue->Enqueue(p);
+    }
+}
+
+  bool
+PointToPointNetDevice::TransmitStart (Packet &p)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << &p << ")");
+  NS_LOG_LOGIC ("UID is " << p.GetUid () << ")");
+//
+// This function is called to start the process of transmitting a packet.
+// We need to tell the channel that we've started wiggling the wire and
+// schedule an event that will be executed when the transmission is complete.
+//
+  NS_ASSERT_MSG(m_txMachineState == READY, "Must be READY to transmit");
+  m_txMachineState = BUSY;
+  Time txTime = Seconds (m_bps.CalculateTxTime(p.GetSize()));
+  Time txCompleteTime = txTime + m_tInterframeGap;
+
+  NS_LOG_LOGIC ("Schedule TransmitCompleteEvent in " << 
+    txCompleteTime.GetSeconds () << "sec");
+  // Schedule the tx complete event
+  Simulator::Schedule (txCompleteTime, 
+                       &PointToPointNetDevice::TransmitComplete, 
+                       this);
+  return m_channel->TransmitStart(p, this, txTime); 
+}
+
+void PointToPointNetDevice::TransmitComplete (void)
+{
+  NS_LOG_FUNCTION;
+//
+// This function is called to finish the  process of transmitting a packet.
+// We need to tell the channel that we've stopped wiggling the wire and
+// get the next packet from the queue.  If the queue is empty, we are
+// done, otherwise transmit the next packet.
+//
+  NS_ASSERT_MSG(m_txMachineState == BUSY, "Must be BUSY if transmitting");
+  m_txMachineState = READY;
+  Packet p;
+  if (!m_queue->Dequeue(p)) return; // Nothing to do at this point
+  TransmitStart(p);
+}
+
+Ptr<TraceResolver> 
+PointToPointNetDevice::GetTraceResolver (void) const
+{
+  NS_LOG_FUNCTION;
+  Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
+  resolver->AddComposite ("queue", m_queue);
+  resolver->AddSource ("rx",
+                       TraceDoc ("receive MAC packet",
+                                 "const Packet &", "packet received"),
+                       m_rxTrace,
+                       PointToPointTraceType ());
+  resolver->SetParentResolver (NetDevice::GetTraceResolver ());
+  return resolver;
+}
+
+bool 
+PointToPointNetDevice::Attach (Ptr<PointToPointChannel> ch)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << &ch << ")");
+
+  m_channel = ch;
+
+  m_channel->Attach(this);
+  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 ();
+
+  /* 
+   * For now, this device is up whenever a channel is attached to it.
+   * In fact, it should become up only when the second device
+   * is attached to the channel. So, there should be a way for
+   * a PointToPointChannel to notify both of its attached devices
+   * that the channel is 'complete', hence that the devices are
+   * up, hence that they can call NotifyLinkUp. 
+   */
+  NotifyLinkUp ();
+  return true;
+}
+
+void PointToPointNetDevice::AddQueue (Ptr<Queue> q)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << q << ")");
+
+  m_queue = q;
+}
+
+void PointToPointNetDevice::Receive (Packet& p)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << &p << ")");
+  uint16_t protocol = 0;
+  Packet packet = p;
+
+  m_rxTrace (packet);
+  ProcessHeader(packet, protocol);
+  ForwardUp (packet, protocol, GetBroadcast ());
+}
+
+Ptr<Queue> PointToPointNetDevice::GetQueue(void) const 
+{ 
+  NS_LOG_FUNCTION;
+  return m_queue;
+}
+
+Ptr<Channel> PointToPointNetDevice::DoGetChannel(void) const 
+{ 
+  NS_LOG_FUNCTION;
+  return m_channel;
+}
+
+bool PointToPointNetDevice::DoNeedsArp (void) const
+{
+  NS_LOG_FUNCTION;
+  return false;
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/point-to-point/point-to-point-net-device.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,308 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 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: Craig Dowell <craigdo@ee.washington.edu>
+ */
+
+#ifndef POINT_TO_POINT_NET_DEVICE_H
+#define POINT_TO_POINT_NET_DEVICE_H
+
+#include <string.h>
+#include "ns3/address.h"
+#include "ns3/node.h"
+#include "ns3/net-device.h"
+#include "ns3/callback.h"
+#include "ns3/packet.h"
+#include "ns3/callback-trace-source.h"
+#include "ns3/nstime.h"
+#include "ns3/data-rate.h"
+#include "ns3/default-value.h"
+#include "ns3/ptr.h"
+
+namespace ns3 {
+
+class Queue;
+class PointToPointChannel;
+
+/**
+ * \brief hold in a TraceContext the type of trace source from a PointToPointNetDevice
+ */
+class PointToPointTraceType : public TraceContextElement
+{
+public:
+  PointToPointTraceType ();
+  void Print (std::ostream &os) const;
+  static uint16_t GetUid (void);
+  std::string GetTypeName (void) const;
+};
+
+/**
+ * \class PointToPointNetDevice
+ * \brief A Device for a Point to Point Network Link.
+ *
+ * Ns-3 takes a four-layer view of a protocol stack.  This is the same model
+ * that TCP uses.  In this view, layers 5-7 of the OSI reference model are
+ * grouped together into an application layer; layer four (transport / TCP) is
+ * broken out; layer three (network / IP) is broken out; and layers 1-2 are
+ * grouped together.  We call this grouping of layers one and two a NetDevice
+ * and represent it as a class in the system.
+ *
+ * The NetDevice class is specialized according to the needs of the specific
+ * kind of network link.  In this case, the link is a PointToPoint link.  The
+ * PointToPoint link is a family of classes that includes this class, the
+ * PointToPointNetDevice, a PointToPointChannel class that represents the 
+ * actual medium across which bits are sent, a PointToPointIpv4Interface class
+ * that provides the hook to tie a general purpose node to this specific
+ * link, and finally, a PointToPointTopology object that is responsible for
+ * putting all of the pieces together.
+ *
+ * This is the PointToPointNetDevice class that represents, essentially, the
+ * PC card that is used to connect to the PointToPoint network.
+ */
+class PointToPointNetDevice : public NetDevice {
+public:
+  /**
+   * Construct a PointToPointNetDevice
+   *
+   * This is the constructor for the PointToPointNetDevice.  It takes as a
+   * parameter the Node to which this device is connected.  Ownership of the
+   * Node pointer is not implied and the node must not be deleded.
+   *
+   * @see PointToPointTopology::AddPointToPointLink ()
+   * @param node the Node to which this device is connected.
+   */
+  PointToPointNetDevice (Ptr<Node> node,
+                         const DataRate& = g_defaultRate.GetValue());
+  /**
+   * Destroy a PointToPointNetDevice
+   *
+   * This is the destructor for the PointToPointNetDevice.
+   */
+  virtual ~PointToPointNetDevice();
+  /**
+   * Set the Data Rate used for transmission of packets.  The data rate is
+   * set in the Attach () method from the corresponding field in the channel
+   * to which the device is attached.  It can be overridden using this method.
+   *
+   * @see Attach ()
+   * @param bps the data rate at which this object operates
+   */
+  void SetDataRate(const DataRate& bps);
+  /**
+   * Set the inteframe gap used to separate packets.  The interframe gap
+   * defines the minimum space required between packets sent by this device.
+   * It is usually set in the Attach () method based on the speed of light
+   * delay of the channel to which the device is attached.  It can be 
+   * overridden using this method if desired.
+   *
+   * @see Attach ()
+   * @param t the interframe gap time
+   */
+  void SetInterframeGap(const Time& t);
+  /**
+   * Attach the device to a channel.
+   *
+   * The PointToPointTopology object creates a PointToPointChannel and two
+   * PointtoPointNetDevices.  In order to introduce these components to each
+   * other, the topology object calls Attach () on each PointToPointNetDevice.
+   * Inside this method, the Net Device calls out to the PointToPointChannel
+   * to introduce itself.
+   *
+   * @see PointToPointTopology::AddPointToPointLink ()
+   * @see SetDataRate ()
+   * @see SetInterframeGap ()
+   * @param ch a pointer to the channel to which this object is being attached.
+   */
+  bool Attach(Ptr<PointToPointChannel> ch);
+  /**
+   * Attach a queue to the PointToPointNetDevice.
+   *
+   * The PointToPointNetDevice "owns" a queue.  This queue is created by the
+   * PointToPointTopology object and implements a queueing method such as
+   * DropTail or RED.  The PointToPointNetDevice assumes ownership of this
+   * queue and must delete it when the device is destroyed.
+   *
+   * @see PointToPointTopology::AddPointToPointLink ()
+   * @see Queue
+   * @see DropTailQueue
+   * @param queue a pointer to the queue for which object is assuming
+   *        ownership.
+   */
+  void AddQueue(Ptr<Queue> queue);
+  /**
+   * Receive a packet from a connected PointToPointChannel.
+   *
+   * The PointToPointNetDevice receives packets from its connected channel
+   * and forwards them up the protocol stack.  This is the public method
+   * used by the channel to indicate that the last bit of a packet has 
+   * arrived at the device.
+   *
+   * @see PointToPointChannel
+   * @param p a reference to the received packet
+   */
+  void Receive (Packet& p);
+protected:
+  /**
+   * Create a Trace Resolver for events in the net device.
+   *
+   * @see class TraceResolver
+   */
+  virtual Ptr<TraceResolver> GetTraceResolver (void) const;
+  virtual void DoDispose (void);
+  /**
+   * Get a copy of the attached Queue.
+   *
+   * This method is provided for any derived class that may need to get
+   * direct access to the underlying queue.
+   *
+   * @see PointToPointTopology
+   * @returns a pointer to the queue.
+   */
+  Ptr<Queue> GetQueue(void) const; 
+  /**
+   * Get a copy of the attached Channel
+   *
+   * This method is provided for any derived class that may need to get
+   * direct access to the connected channel
+   *
+   * @see PointToPointChannel
+   * @returns a pointer to the channel
+   */
+  virtual Ptr<Channel> DoGetChannel(void) const;
+  /**
+   * Set a new default data rate
+   */
+  static void SetDefaultRate(const DataRate&);
+
+  /** 
+   * Get the current default rate.
+   * @returns a const reference to current default
+   */
+
+  static const DataRate& GetDefaultRate();
+
+private:
+  /**
+   * Adds the necessary headers and trailers to a packet of data in order to
+   * respect the protocol implemented by the agent.
+   */
+  void AddHeader(Packet& p, uint16_t protocolNumber);
+  /**
+   * Removes, from a packet of data, all headers and trailers that
+   * relate to the protocol implemented by the agent
+   * \return Returns true if the packet should be forwarded up the
+   * protocol stack.
+   */
+  bool ProcessHeader(Packet& p, uint16_t& param);
+  /**
+   * Send a Packet Down the Wire.
+   *
+   * The SendTo method is defined as the standard way that the level three
+   * protocol uses to tell a NetDevice to send a packet.  SendTo is declared
+   * as abstract in the NetDevice class and we declare it here.
+   *
+   * @see NetDevice
+   * @param p a reference to the packet to send
+   * @param dest a reference to the Address of the destination device
+   * @param protocolNumber Protocol Number used to find protocol touse
+   * @returns true if success, false on failure
+   */
+  virtual bool SendTo (const Packet& p, const Address& dest, 
+                       uint16_t protocolNumber);
+  /**
+   * Start Sending a Packet Down the Wire.
+   *
+   * The TransmitStart method is the method that is used internally in the
+   * PointToPointNetDevice to begin the process of sending a packet out on
+   * the channel.  The corresponding method is called on the channel to let
+   * it know that the physical device this class represents has virually
+   * started sending signals.  An event is scheduled for the time at which
+   * the bits have been completely transmitted.
+   *
+   * @see PointToPointChannel::TransmitStart ()
+   * @see TransmitCompleteEvent ()
+   * @param p a reference to the packet to send
+   * @returns true if success, false on failure
+   */
+  bool TransmitStart (Packet &p);
+  /**
+   * Stop Sending a Packet Down the Wire and Begin the Interframe Gap.
+   *
+   * The TransmitComplete method is used internally to finish the process
+   * of sending a packet out on the channel.
+   *
+   */
+  void TransmitComplete(void);
+  virtual bool DoNeedsArp (void) const;
+  /**
+   * Enumeration of the states of the transmit machine of the net device.
+   */
+  enum TxMachineState
+    {
+      READY, /**< The transmitter is ready to begin transmission of a packet */
+      BUSY   /**< The transmitter is busy transmitting a packet */
+    };
+  /**
+   * The state of the Net Device transmit state machine.
+   * @see TxMachineState
+   */
+  TxMachineState m_txMachineState;
+  /**
+   * The data rate that the Net Device uses to simulate packet transmission
+   * timing.
+   * @see class DataRate
+   */
+  DataRate       m_bps;
+  /**
+   * The interframe gap that the Net Device uses to throttle packet
+   * transmission
+   * @see class Time
+   */
+  Time           m_tInterframeGap;
+  /**
+   * The PointToPointChannel to which this PointToPointNetDevice has been
+   * attached.
+   * @see class PointToPointChannel
+   */
+  Ptr<PointToPointChannel> m_channel;
+  /**
+   * The Queue which this PointToPointNetDevice uses as a packet source.
+   * Management of this Queue has been delegated to the PointToPointNetDevice
+   * and it has the responsibility for deletion.
+   * @see class Queue
+   * @see class DropTailQueue
+   */
+  Ptr<Queue> m_queue;
+  /**
+   * The trace source for the packet reception events that the device can
+   * fire.
+   *
+   * @see class CallBackTraceSource
+   * @see class TraceResolver
+   */
+  CallbackTraceSource<const Packet &> m_rxTrace;
+  /** 
+   * Default data rate.  Used for all newly created p2p net devices
+   */
+   static DataRateDefaultValue g_defaultRate;
+
+};
+
+}; // namespace ns3
+
+#endif // POINT_TO_POINT_NET_DEVICE_H
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/point-to-point/point-to-point-topology.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,172 @@
+/* -*- 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
+//
+// Author: George F. Riley<riley@ece.gatech.edu>
+//
+
+//
+// Topology helper for ns3.
+// George F. Riley, Georgia Tech, Spring 2007
+
+#include <algorithm>
+#include "ns3/assert.h"
+#include "ns3/log.h"
+#include "ns3/fatal-error.h"
+#include "ns3/nstime.h"
+#include "ns3/internet-node.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/ipv4.h"
+#include "ns3/queue.h"
+
+#include "point-to-point-channel.h"
+#include "point-to-point-net-device.h"
+#include "point-to-point-topology.h"
+
+namespace ns3 {
+
+Ptr<PointToPointChannel>
+PointToPointTopology::AddPointToPointLink(
+  Ptr<Node> n1,
+  Ptr<Node> n2,
+  const DataRate& bps,
+  const Time& delay)
+{
+  Ptr<PointToPointChannel> channel = Create<PointToPointChannel> (bps, delay);
+
+  Ptr<PointToPointNetDevice> net1 = Create<PointToPointNetDevice> (n1);
+
+  Ptr<Queue> q = Queue::CreateDefault ();
+  net1->AddQueue(q);
+  net1->Attach (channel);
+  
+  Ptr<PointToPointNetDevice> net2 = Create<PointToPointNetDevice> (n2);
+
+  q = Queue::CreateDefault ();
+  net2->AddQueue(q);
+  net2->Attach (channel);
+
+  return channel;
+}
+
+void
+PointToPointTopology::AddIpv4Addresses(
+  Ptr<const PointToPointChannel> chan,
+  Ptr<Node> n1, const Ipv4Address& addr1,
+  Ptr<Node> n2, const Ipv4Address& addr2)
+{
+
+  // Duplex link is assumed to be subnetted as a /30
+  // May run this unnumbered in the future?
+  Ipv4Mask netmask("255.255.255.252");
+  NS_ASSERT (netmask.IsMatch(addr1,addr2));
+
+  // The PointToPoint channel is used to find the relevant NetDevices
+  NS_ASSERT (chan->GetNDevices () == 2);
+  Ptr<NetDevice> nd1 = chan->GetDevice (0);
+  Ptr<NetDevice> nd2 = chan->GetDevice (1);
+  // Make sure that nd1 belongs to n1 and nd2 to n2
+  if ( (nd1->GetNode ()->GetId () == n2->GetId () ) && 
+       (nd2->GetNode ()->GetId () == n1->GetId () ) )
+    {
+      std::swap(nd1, nd2);
+    }
+  NS_ASSERT (nd1->GetNode ()->GetId () == n1->GetId ());
+  NS_ASSERT (nd2->GetNode ()->GetId () == n2->GetId ());
+  
+  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);
+
+  Ptr<Ipv4> ip2 = n2->QueryInterface<Ipv4> (Ipv4::iid);
+  uint32_t index2 = ip2->AddInterface (nd2);
+
+  ip2->SetAddress (index2, addr2);
+  ip2->SetNetworkMask (index2, netmask);
+  ip2->SetUp (index2);
+  
+}
+
+void
+PointToPointTopology::AddIpv4Routes (
+  Ptr<Node> n1, Ptr<Node> n2, Ptr<const PointToPointChannel> chan)
+{ 
+  // The PointToPoint channel is used to find the relevant NetDevices
+  NS_ASSERT (chan->GetNDevices () == 2);
+  Ptr<NetDevice> nd1 = chan->GetDevice (0);
+  Ptr<NetDevice> nd2 = chan->GetDevice (1);
+
+  // Assert that n1 is the Node owning one of the two NetDevices
+  // and make sure that nd1 corresponds to it
+  if (nd1->GetNode ()->GetId () == n1->GetId ())
+    {
+      ; // Do nothing
+    }
+  else if (nd2->GetNode ()->GetId () == n1->GetId ())
+    {
+      std::swap(nd1, nd2);
+    }
+  else
+    {
+      NS_FATAL_ERROR("P2PTopo: Node does not contain an interface on Channel");
+    }
+
+   // Assert that n2 is the Node owning one of the two NetDevices
+   // and make sure that nd2 corresponds to it
+  if (nd2->GetNode ()->GetId () != n2->GetId ())
+    {
+      NS_FATAL_ERROR("P2PTopo: Node does not contain an interface on Channel");
+    }
+
+  // Assert that both are Ipv4 nodes
+  Ptr<Ipv4> ip1 = nd1->GetNode ()->QueryInterface<Ipv4> (Ipv4::iid);
+  Ptr<Ipv4> ip2 = nd2->GetNode ()->QueryInterface<Ipv4> (Ipv4::iid);
+  NS_ASSERT(ip1 != 0 && ip2 != 0);
+
+  // Get interface indexes for both nodes corresponding to the right channel
+  uint32_t index1 = 0;
+  bool found = false;
+  for (uint32_t i = 0; i < ip1->GetNInterfaces (); i++)
+    {
+      if (ip1 ->GetNetDevice (i) == nd1)
+        {
+          index1 = i;
+          found = true;
+        }
+    }
+  NS_ASSERT(found);
+
+  uint32_t index2 = 0;
+  found = false;
+  for (uint32_t i = 0; i < ip2->GetNInterfaces (); i++)
+    {
+      if (ip2 ->GetNetDevice (i) == nd2)
+        {
+          index2 = i;
+          found = true;
+        }
+    }
+  NS_ASSERT(found);
+
+  ip1->AddHostRouteTo (ip2-> GetAddress (index2), index1);
+  ip2->AddHostRouteTo (ip1-> GetAddress (index1), index2); 
+}
+
+} // namespace ns3
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/point-to-point/point-to-point-topology.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,87 @@
+/* -*- 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
+//
+// Author: George F. Riley<riley@ece.gatech.edu>
+//
+// Topology helper for ns3.
+// George F. Riley, Georgia Tech, Spring 2007
+#ifndef __POINT_TO_POINT_TOPOLOGY_H__
+#define __POINT_TO_POINT_TOPOLOGY_H__
+
+#include "ns3/ptr.h"
+
+// The topology class consists of only static methods thar are used to
+// create the topology and data flows for an ns3 simulation
+
+namespace ns3 {
+
+class PointToPointChannel;
+class Node;
+class IPAddr;
+class DataRate;
+class Queue;
+
+/**
+ * \brief A helper class to create Topologies based on the 
+ * ns3::PointToPointNetDevice and  ns3::PointToPointChannel objects.
+ */
+class PointToPointTopology {
+public:
+  /** 
+   * \param n1 Node
+   * \param n2 Node
+   * \param dataRate Maximum transmission link rate 
+   * \param delay one-way propagation delay 
+   * \return Pointer to the underlying PointToPointChannel
+   * 
+   * Add a full-duplex point-to-point link between two nodes
+   * and attach PointToPointNetDevices to the resulting
+   * PointToPointChannel.  
+   */
+  static Ptr<PointToPointChannel> AddPointToPointLink(
+    Ptr<Node> n1, Ptr<Node> n2, const DataRate& dataRate, const Time& delay);
+
+  /** 
+   * \param chan PointToPointChannel to use
+   * \param n1 Node
+   * \param addr1 Ipv4 Address for n1
+   * \param n2 Node
+   * \param addr2 Ipv4 Address for n2
+   * 
+   * Add Ipv4Addresses to the Ipv4 interfaces associated with the 
+   * two PointToPointNetDevices on the provided PointToPointChannel
+   */
+  static void AddIpv4Addresses(
+    Ptr<const PointToPointChannel> chan,
+    Ptr<Node> n1, const Ipv4Address& addr1,
+    Ptr<Node> n2, const Ipv4Address& addr2);
+
+  /**
+   * \param channel PointToPointChannel to use
+   * \param n1 Node
+   * \param n2 Node
+   * 
+   * For the given PointToPointChannel, for each Node, add an 
+   * IPv4 host route to the IPv4 address of the peer node.  
+   */
+  static void AddIpv4Routes (Ptr<Node> n1, Ptr<Node> n2, Ptr<const PointToPointChannel> channel);
+};
+
+} // namespace ns3
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/point-to-point/waf	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,1 @@
+exec "`dirname "$0"`"/../../../waf "$@"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/point-to-point/wscript	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,17 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+
+def build(bld):
+    module = bld.create_ns3_module('point-to-point', ['node'])
+    module.source = [
+        'point-to-point-net-device.cc',
+        'point-to-point-channel.cc',
+        'point-to-point-topology.cc',
+        ]
+    headers = bld.create_obj('ns3header')
+    headers.source = [
+        'point-to-point-net-device.h',
+        'point-to-point-channel.h',
+        'point-to-point-topology.h',
+        ]
+
--- a/src/internet-node/arp-cache.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/arp-cache.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -19,16 +19,16 @@
  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
  */
 #include "ns3/assert.h"
-
 #include "ns3/packet.h"
 #include "ns3/simulator.h"
 
 #include "arp-cache.h"
 #include "arp-header.h"
+#include "ipv4-interface.h"
 
 namespace ns3 {
 
-ArpCache::ArpCache (Ptr<NetDevice> device, Ipv4Interface *interface)
+ArpCache::ArpCache (Ptr<NetDevice> device, Ptr<Ipv4Interface> interface)
   : m_device (device), 
     m_interface (interface),
     m_aliveTimeout (Seconds (120)),
@@ -47,7 +47,7 @@
   return m_device;
 }
 
-Ipv4Interface *
+Ptr<Ipv4Interface>
 ArpCache::GetInterface (void) const
 {
   return m_interface;
@@ -109,6 +109,8 @@
 ArpCache::Entry *
 ArpCache::Add (Ipv4Address to)
 {
+  NS_ASSERT (m_arpCache.find (to) == m_arpCache.end ());
+
   ArpCache::Entry *entry = new ArpCache::Entry (this);
   m_arpCache[to] = entry;  
   return entry;
@@ -146,7 +148,7 @@
   UpdateSeen ();
 }
 Packet 
-ArpCache::Entry::MarkAlive (MacAddress macAddress) 
+ArpCache::Entry::MarkAlive (Address macAddress) 
 {
   NS_ASSERT (m_state == WAIT_REPLY);
   //NS_ASSERT (m_waiting != 0);
@@ -180,7 +182,7 @@
   UpdateSeen ();
 }
 
-MacAddress
+Address
 ArpCache::Entry::GetMacAddress (void)
 {
   NS_ASSERT (m_state == ALIVE);
--- a/src/internet-node/arp-cache.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/arp-cache.h	Fri Sep 28 11:59:46 2007 +0100
@@ -26,7 +26,7 @@
 #include "ns3/nstime.h"
 #include "ns3/net-device.h"
 #include "ns3/ipv4-address.h"
-#include "ns3/mac-address.h"
+#include "ns3/address.h"
 #include "ns3/ptr.h"
 #include "sgi-hashmap.h"
 
@@ -48,7 +48,7 @@
    * \param device The hardware NetDevice associated with this ARP chache
    * \param interface the Ipv4Interface associated with this ARP chache
    */
-  ArpCache (Ptr<NetDevice> device, Ipv4Interface *interface);
+  ArpCache (Ptr<NetDevice> device, Ptr<Ipv4Interface> interface);
   ~ArpCache ();
   /**
    * \return The NetDevice that this ARP cache is associated with
@@ -57,7 +57,7 @@
   /**
    * \return the Ipv4Interface that this ARP cache is associated with
    */
-  Ipv4Interface *GetInterface (void) const;
+  Ptr<Ipv4Interface> GetInterface (void) const;
   
   void SetAliveTimeout (Time aliveTimeout);
   void SetDeadTimeout (Time deadTimeout);
@@ -101,7 +101,7 @@
      * \param macAddress
      * \return 
      */
-    Packet MarkAlive (MacAddress macAddress);
+    Packet MarkAlive (Address macAddress);
     /**
      * \param waiting
      */
@@ -127,7 +127,7 @@
     /**
      * \return The MacAddress of this entry
      */
-    MacAddress GetMacAddress (void);
+    Address GetMacAddress (void);
     /**
      * \return True if this entry has timedout; false otherwise.
      */
@@ -143,7 +143,7 @@
     ArpCache *m_arp;
     ArpCacheEntryState_e m_state;
     Time m_lastSeen;
-    MacAddress m_macAddress;
+    Address m_macAddress;
     Packet m_waiting;
   };
 
@@ -152,7 +152,7 @@
   typedef sgi::hash_map<Ipv4Address, ArpCache::Entry *, Ipv4AddressHash>::iterator CacheI;
 
   Ptr<NetDevice> m_device;
-  Ipv4Interface *m_interface;
+  Ptr<Ipv4Interface> m_interface;
   Time m_aliveTimeout;
   Time m_deadTimeout;
   Time m_waitReplyTimeout;
--- a/src/internet-node/arp-header.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/arp-header.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -20,18 +20,24 @@
  */
 
 #include "ns3/assert.h"
+#include "ns3/address-utils.h"
 #include "arp-header.h"
-#include "header-utils.h"
 
 namespace ns3 {
 
-ArpHeader::~ArpHeader ()
-{}
+NS_HEADER_ENSURE_REGISTERED (ArpHeader);
+
+uint32_t
+ArpHeader::GetUid (void)
+{
+  static uint32_t uid = AllocateUid<ArpHeader> ("ArpHeader.ns3");
+  return uid;
+}
 
 void 
-ArpHeader::SetRequest (MacAddress sourceHardwareAddress,
+ArpHeader::SetRequest (Address sourceHardwareAddress,
                        Ipv4Address sourceProtocolAddress,
-                       MacAddress destinationHardwareAddress,
+                       Address destinationHardwareAddress,
                        Ipv4Address destinationProtocolAddress)
 {
   m_type = ARP_TYPE_REQUEST;
@@ -41,9 +47,9 @@
   m_ipv4Dest = destinationProtocolAddress;
 }
 void 
-ArpHeader::SetReply (MacAddress sourceHardwareAddress,
+ArpHeader::SetReply (Address sourceHardwareAddress,
                      Ipv4Address sourceProtocolAddress,
-                     MacAddress destinationHardwareAddress,
+                     Address destinationHardwareAddress,
                      Ipv4Address destinationProtocolAddress)
 {
   m_type = ARP_TYPE_REPLY;
@@ -62,12 +68,12 @@
 {
   return (m_type == ARP_TYPE_REPLY)?true:false;
 }
-MacAddress 
+Address 
 ArpHeader::GetSourceHardwareAddress (void)
 {
   return m_macSource;
 }
-MacAddress 
+Address 
 ArpHeader::GetDestinationHardwareAddress (void)
 {
   return m_macDest;
@@ -83,24 +89,36 @@
   return m_ipv4Dest;
 }
 
+std::string 
+ArpHeader::GetName (void) const
+{
+  return "ARP";
+}
 
 void 
-ArpHeader::PrintTo (std::ostream &os) const
+ArpHeader::Print (std::ostream &os) const
 {
-  os << "(arp)";
   if (IsRequest ()) 
     {
-      os << " source mac: " << m_macSource
-          << " source ipv4: " << m_ipv4Source
-          << " dest ipv4: " << m_ipv4Dest;
+      os << "("
+         << "request "
+         << "source mac: " << m_macSource << " "
+         << "source ipv4: " << m_ipv4Source << " "
+         << "dest ipv4: " << m_ipv4Dest
+         << ")"
+        ;
     } 
   else 
     {
       NS_ASSERT (IsReply ());
-      os << " source mac: " << m_macSource
-          << " source ipv4: " << m_ipv4Source
-          << " dest mac: " << m_macDest
-          << " dest ipv4: " <<m_ipv4Dest;
+      os << "("
+         << "reply " 
+         << "source mac: " << m_macSource << " "
+         << "source ipv4: " << m_ipv4Source << " "
+         << "dest mac: " << m_macDest << " "
+         << "dest ipv4: " <<m_ipv4Dest
+         << ")"
+        ;
     }
 }
 uint32_t 
@@ -111,7 +129,7 @@
 }
 
 void
-ArpHeader::SerializeTo (Buffer::Iterator start) const
+ArpHeader::Serialize (Buffer::Iterator start) const
 {
   Buffer::Iterator i = start;
   NS_ASSERT (m_macSource.GetLength () == m_macDest.GetLength ());
@@ -129,7 +147,7 @@
   WriteTo (i, m_ipv4Dest);
 }
 uint32_t
-ArpHeader::DeserializeFrom (Buffer::Iterator start)
+ArpHeader::Deserialize (Buffer::Iterator start)
 {
   Buffer::Iterator i = start;
   i.Next (2+2);
--- a/src/internet-node/arp-header.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/arp-header.h	Fri Sep 28 11:59:46 2007 +0100
@@ -23,58 +23,47 @@
 #define ARP_HEADER_H
 
 #include "ns3/header.h"
-#include "ns3/mac-address.h"
+#include "ns3/address.h"
 #include "ns3/ipv4-address.h"
+#include <string>
 
 namespace ns3 {
 /**
  * \brief The packet header for an ARP packet
  */
-class ArpHeader : public Header {
- public:
-  virtual ~ArpHeader ();
+class ArpHeader : public Header 
+{
+public:
+  static uint32_t GetUid (void);
 
-  void SetRequest (MacAddress sourceHardwareAddress,
+  void SetRequest (Address sourceHardwareAddress,
                    Ipv4Address sourceProtocolAddress,
-                   MacAddress destinationHardwareAddress,
+                   Address destinationHardwareAddress,
                    Ipv4Address destinationProtocolAddress);
-  void SetReply (MacAddress sourceHardwareAddress,
+  void SetReply (Address sourceHardwareAddress,
                  Ipv4Address sourceProtocolAddress,
-                 MacAddress destinationHardwareAddress,
+                 Address destinationHardwareAddress,
                  Ipv4Address destinationProtocolAddress);
   bool IsRequest (void) const;
   bool IsReply (void) const;
-  MacAddress GetSourceHardwareAddress (void);
-  MacAddress GetDestinationHardwareAddress (void);
+  Address GetSourceHardwareAddress (void);
+  Address GetDestinationHardwareAddress (void);
   Ipv4Address GetSourceIpv4Address (void);
   Ipv4Address GetDestinationIpv4Address (void);
 
-private:
-  /**
-   * \param os
-   */
-  virtual void PrintTo (std::ostream &os) const;
-  /**
-   * \return
-   */
-  virtual uint32_t GetSerializedSize (void) const;
-  /**
-   * \param start
-   */
-  virtual void SerializeTo (Buffer::Iterator start) const;
-  /**
-   * \param start
-   * \return
-   */
-  virtual uint32_t DeserializeFrom (Buffer::Iterator start);
+  std::string GetName (void) const;
+  void Print (std::ostream &os) const;
+  uint32_t GetSerializedSize (void) const;
+  void Serialize (Buffer::Iterator start) const;
+  uint32_t Deserialize (Buffer::Iterator start);
 
   enum ArpType_e {
     ARP_TYPE_REQUEST = 1,
     ARP_TYPE_REPLY   = 2
   };
   uint16_t m_type;
-  MacAddress m_macSource;
-  MacAddress m_macDest;
+  Address m_macSource;
+  Address m_macDest;
   Ipv4Address m_ipv4Source;
   Ipv4Address m_ipv4Dest;
 };
--- a/src/internet-node/arp-ipv4-interface.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/arp-ipv4-interface.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -21,54 +21,95 @@
  */
 
 #include "ns3/packet.h"
+#include "ns3/log.h"
 #include "ns3/composite-trace-resolver.h"
 #include "ns3/node.h"
 #include "ns3/net-device.h"
+#include "ns3/address.h"
 
 #include "arp-ipv4-interface.h"
-#include "arp-private.h"
 #include "ipv4-l3-protocol.h"
+#include "arp-l3-protocol.h"
+
+NS_LOG_COMPONENT_DEFINE ("ArpIpv4Interface");
 
 namespace ns3 {
 
 ArpIpv4Interface::ArpIpv4Interface (Ptr<Node> node, Ptr<NetDevice> device)
   : Ipv4Interface (device),
     m_node (node)
-{}
-ArpIpv4Interface::~ArpIpv4Interface ()
-{}
+{
+  NS_LOG_FUNCTION;
+}
 
-TraceResolver *
-ArpIpv4Interface::DoCreateTraceResolver (TraceContext const &context)
+ArpIpv4Interface::~ArpIpv4Interface ()
 {
-  CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
+  NS_LOG_FUNCTION;
+}
+
+Ptr<TraceResolver>
+ArpIpv4Interface::GetTraceResolver (void) const
+{
+  NS_LOG_FUNCTION;
+  Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
   if (GetDevice () != 0)
     {
-      resolver->Add ("netdevice",
-                     MakeCallback (&NetDevice::CreateTraceResolver, PeekPointer (GetDevice ())),
-                     ArpIpv4Interface::NETDEVICE);
+      resolver->AddComposite ("netdevice", GetDevice ());
     }
-  
+  resolver->SetParentResolver (Ipv4Interface::GetTraceResolver ());
   return resolver;
 }
 
 void 
 ArpIpv4Interface::SendTo (Packet p, Ipv4Address dest)
 {
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << &p << ", " << dest << ")");
+
   NS_ASSERT (GetDevice () != 0);
   if (GetDevice ()->NeedsArp ())
     {
-      Ptr<ArpPrivate> arp = m_node->QueryInterface<ArpPrivate> (ArpPrivate::iid);
-      MacAddress hardwareDestination;
-      bool found = arp->Lookup (p, dest, GetDevice (), &hardwareDestination);
+      NS_LOG_LOGIC ("Needs ARP");
+      Ptr<ArpL3Protocol> arp = 
+        m_node->QueryInterface<ArpL3Protocol> (ArpL3Protocol::iid);
+      Address hardwareDestination;
+      bool found;
+      
+      if (dest.IsBroadcast () || 
+          dest.IsSubnetDirectedBroadcast (GetNetworkMask ()) )
+        {
+          NS_LOG_LOGIC ("IsBroadcast");
+          hardwareDestination = GetDevice ()->GetBroadcast ();
+          found = true;
+        }
+      else if (dest.IsMulticast ())
+        {
+          NS_LOG_LOGIC ("IsMulticast");
+          NS_ASSERT_MSG(GetDevice ()->IsMulticast (),
+            "ArpIpv4Interface::SendTo (): Sending multicast packet over "
+            "non-multicast device");
+
+          hardwareDestination = GetDevice ()->MakeMulticastAddress(dest);
+          found = true;
+        }
+      else
+        {
+          NS_LOG_LOGIC ("ARP Lookup");
+          found = arp->Lookup (p, dest, GetDevice (), &hardwareDestination);
+        }
+
       if (found)
         {
-          GetDevice ()->Send (p, hardwareDestination, Ipv4L3Protocol::PROT_NUMBER);
+          NS_LOG_LOGIC ("Address Resolved.  Send.");
+          GetDevice ()->Send (p, hardwareDestination, 
+            Ipv4L3Protocol::PROT_NUMBER);
         }
     }
   else
     {
-      GetDevice ()->Send (p, GetDevice ()->GetBroadcast (), Ipv4L3Protocol::PROT_NUMBER);
+      NS_LOG_LOGIC ("Doesn't need ARP");
+      GetDevice ()->Send (p, GetDevice ()->GetBroadcast (), 
+        Ipv4L3Protocol::PROT_NUMBER);
     }
 }
 
--- a/src/internet-node/arp-ipv4-interface.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/arp-ipv4-interface.h	Fri Sep 28 11:59:46 2007 +0100
@@ -39,16 +39,13 @@
 class ArpIpv4Interface : public Ipv4Interface
 {
  public:
-  enum TraceType {
-    NETDEVICE,
-    ARP,
-  };
   ArpIpv4Interface (Ptr<Node> node, Ptr<NetDevice> device);
   virtual ~ArpIpv4Interface ();
 
- private:
+protected:
+  virtual Ptr<TraceResolver> GetTraceResolver (void) const;
+private:
   virtual void SendTo (Packet p, Ipv4Address dest);
-  virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context);
   Ptr<Node> m_node;
 };
 
--- a/src/internet-node/arp-l3-protocol.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/arp-l3-protocol.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -19,52 +19,52 @@
  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
  */
 #include "ns3/packet.h"
-#include "ns3/debug.h"
-#include "ns3/empty-trace-resolver.h"
+#include "ns3/log.h"
 #include "ns3/node.h"
 #include "ns3/net-device.h"
 
+#include "ipv4-l3-protocol.h"
 #include "arp-l3-protocol.h"
 #include "arp-header.h"
 #include "arp-cache.h"
 #include "ipv4-interface.h"
-#include "ipv4-private.h"
 
-NS_DEBUG_COMPONENT_DEFINE ("ArpL3Protocol");
+NS_LOG_COMPONENT_DEFINE ("ArpL3Protocol");
 
 namespace ns3 {
 
+const InterfaceId ArpL3Protocol::iid = MakeInterfaceId ("ArpL3Protocol", Object::iid);
 const uint16_t ArpL3Protocol::PROT_NUMBER = 0x0806;
 
 ArpL3Protocol::ArpL3Protocol (Ptr<Node> node)
-  : L3Protocol (PROT_NUMBER, 0/* XXX: correct version number ? */ ),
-    m_node (node)
-{}
+  : m_node (node)
+{
+  NS_LOG_FUNCTION;
+  SetInterfaceId (ArpL3Protocol::iid);
+}
 
 ArpL3Protocol::~ArpL3Protocol ()
-{}
+{
+  NS_LOG_FUNCTION;
+}
 
 void 
 ArpL3Protocol::DoDispose (void)
 {
+  NS_LOG_FUNCTION;
   for (CacheList::const_iterator i = m_cacheList.begin (); i != m_cacheList.end (); i++)
     {
       delete *i;
     }
   m_cacheList.clear ();
   m_node = 0;
-  L3Protocol::DoDispose ();
-}
-
-TraceResolver *
-ArpL3Protocol::CreateTraceResolver (TraceContext const &context)
-{
-  return new EmptyTraceResolver (context);
+  Object::DoDispose ();
 }
 
 ArpCache *
 ArpL3Protocol::FindCache (Ptr<NetDevice> device)
 {
+  NS_LOG_FUNCTION;
   for (CacheList::const_iterator i = m_cacheList.begin (); i != m_cacheList.end (); i++)
     {
       if ((*i)->GetDevice () == device)
@@ -72,8 +72,8 @@
 	  return *i;
 	}
     }
-  Ptr<Ipv4Private> ipv4 = m_node->QueryInterface<Ipv4Private> (Ipv4Private::iid);
-  Ipv4Interface *interface = ipv4->FindInterfaceForDevice (device);
+  Ptr<Ipv4L3Protocol> ipv4 = m_node->QueryInterface<Ipv4L3Protocol> (Ipv4L3Protocol::iid);
+  Ptr<Ipv4Interface> interface = ipv4->FindInterfaceForDevice (device);
   ArpCache * cache = new ArpCache (device, interface);
   NS_ASSERT (device->IsBroadcast ());
   device->SetLinkChangeCallback (MakeCallback (&ArpCache::Flush, cache));
@@ -82,22 +82,31 @@
 }
 
 void 
-ArpL3Protocol::Receive(Packet& packet, Ptr<NetDevice> device)
+ArpL3Protocol::Receive(Ptr<NetDevice> device, const Packet& p, uint16_t protocol, const Address &from)
 {
+  NS_LOG_FUNCTION;
   ArpCache *cache = FindCache (device);
   ArpHeader arp;
+  Packet packet = p;
   packet.RemoveHeader (arp);
+  
+  NS_LOG_LOGIC ("ARP: received "<< (arp.IsRequest ()? "request" : "reply") <<
+            " node="<<m_node->GetId ()<<", got request from " <<
+            arp.GetSourceIpv4Address () << " for address " <<
+            arp.GetDestinationIpv4Address () << "; we have address " <<
+            cache->GetInterface ()->GetAddress ());
+
   if (arp.IsRequest () && 
       arp.GetDestinationIpv4Address () == cache->GetInterface ()->GetAddress ()) 
     {
-      NS_DEBUG ("node="<<m_node->GetId () <<", got request from " << 
+      NS_LOG_LOGIC ("node="<<m_node->GetId () <<", got request from " << 
                 arp.GetSourceIpv4Address () << " -- send reply");
       SendArpReply (cache, arp.GetSourceIpv4Address (),
                     arp.GetSourceHardwareAddress ());
     } 
   else if (arp.IsReply () &&
            arp.GetDestinationIpv4Address ().IsEqual (cache->GetInterface ()->GetAddress ()) &&
-           arp.GetDestinationHardwareAddress ().IsEqual (device->GetAddress ())) 
+           arp.GetDestinationHardwareAddress () == device->GetAddress ()) 
     {
       Ipv4Address from = arp.GetSourceIpv4Address ();
       ArpCache::Entry *entry = cache->Lookup (from);
@@ -105,10 +114,10 @@
         {
           if (entry->IsWaitReply ()) 
             {
-              NS_DEBUG ("node="<<m_node->GetId ()<<", got reply from " << 
+              NS_LOG_LOGIC ("node="<<m_node->GetId ()<<", got reply from " << 
                         arp.GetSourceIpv4Address ()
                      << " for waiting entry -- flush");
-              MacAddress from_mac = arp.GetSourceHardwareAddress ();
+              Address from_mac = arp.GetSourceHardwareAddress ();
               Packet waiting = entry->MarkAlive (from_mac);
 	      cache->GetInterface ()->Send (waiting, arp.GetSourceIpv4Address ());
             } 
@@ -116,7 +125,7 @@
             {
               // ignore this reply which might well be an attempt 
               // at poisening my arp cache.
-              NS_DEBUG ("node="<<m_node->GetId ()<<", got reply from " << 
+              NS_LOG_LOGIC("node="<<m_node->GetId ()<<", got reply from " << 
                         arp.GetSourceIpv4Address () << 
                         " for non-waiting entry -- drop");
 	      // XXX report packet as dropped.
@@ -124,16 +133,23 @@
         } 
       else 
         {
-          NS_DEBUG ("node="<<m_node->GetId ()<<", got reply for unknown entry -- drop");
+          NS_LOG_LOGIC ("node="<<m_node->GetId ()<<", got reply for unknown entry -- drop");
 	  // XXX report packet as dropped.
         }
     }
+  else
+    {
+      NS_LOG_LOGIC ("node="<<m_node->GetId ()<<", got request from " <<
+                arp.GetSourceIpv4Address () << " for unknown address " <<
+                arp.GetDestinationIpv4Address () << " -- drop");
+    }
 }
 bool 
 ArpL3Protocol::Lookup (Packet &packet, Ipv4Address destination, 
-	     Ptr<NetDevice> device,
-	     MacAddress *hardwareDestination)
+                       Ptr<NetDevice> device,
+                       Address *hardwareDestination)
 {
+  NS_LOG_FUNCTION;
   ArpCache *cache = FindCache (device);
   ArpCache::Entry *entry = cache->Lookup (destination);
   if (entry != 0)
@@ -142,21 +158,21 @@
         {
           if (entry->IsDead ()) 
             {
-              NS_DEBUG ("node="<<m_node->GetId ()<<
+              NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
                         ", dead entry for " << destination << " expired -- send arp request");
               entry->MarkWaitReply (packet);
               SendArpRequest (cache, destination);
             } 
           else if (entry->IsAlive ()) 
             {
-              NS_DEBUG ("node="<<m_node->GetId ()<<
+              NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
                         ", alive entry for " << destination << " expired -- send arp request");
               entry->MarkWaitReply (packet);
               SendArpRequest (cache, destination);
             } 
           else if (entry->IsWaitReply ()) 
             {
-              NS_DEBUG ("node="<<m_node->GetId ()<<
+              NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
                         ", wait reply for " << destination << " expired -- drop");
               entry->MarkDead ();
 	      // XXX report packet as 'dropped'
@@ -166,20 +182,20 @@
         {
           if (entry->IsDead ()) 
             {
-              NS_DEBUG ("node="<<m_node->GetId ()<<
+              NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
                         ", dead entry for " << destination << " valid -- drop");
 	      // XXX report packet as 'dropped'
             } 
           else if (entry->IsAlive ()) 
             {
-              NS_DEBUG ("node="<<m_node->GetId ()<<
+              NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
                         ", alive entry for " << destination << " valid -- send");
 	      *hardwareDestination = entry->GetMacAddress ();
               return true;
             } 
           else if (entry->IsWaitReply ()) 
             {
-              NS_DEBUG ("node="<<m_node->GetId ()<<
+              NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
                         ", wait reply for " << destination << " valid -- drop previous");
               Packet old = entry->UpdateWaitReply (packet);
 	      // XXX report 'old' packet as 'dropped'
@@ -190,7 +206,7 @@
   else
     {
       // This is our first attempt to transmit data to this destination.
-      NS_DEBUG ("node="<<m_node->GetId ()<<
+      NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
                 ", no entry for " << destination << " -- send arp request");
       entry = cache->Add (destination);
       entry->MarkWaitReply (packet);
@@ -202,7 +218,13 @@
 void
 ArpL3Protocol::SendArpRequest (ArpCache const *cache, Ipv4Address to)
 {
+  NS_LOG_FUNCTION;
   ArpHeader arp;
+  NS_LOG_LOGIC ("ARP: sending request from node "<<m_node->GetId ()<<
+            " || src: " << cache->GetDevice ()->GetAddress () <<
+            " / " << cache->GetInterface ()->GetAddress () <<
+            " || dst: " << cache->GetDevice ()->GetBroadcast () <<
+            " / " << to);
   arp.SetRequest (cache->GetDevice ()->GetAddress (),
 		  cache->GetInterface ()->GetAddress (), 
                   cache->GetDevice ()->GetBroadcast (),
@@ -213,9 +235,14 @@
 }
 
 void
-ArpL3Protocol::SendArpReply (ArpCache const *cache, Ipv4Address toIp, MacAddress toMac)
+ArpL3Protocol::SendArpReply (ArpCache const *cache, Ipv4Address toIp, Address toMac)
 {
+  NS_LOG_FUNCTION;
   ArpHeader arp;
+  NS_LOG_LOGIC ("ARP: sending reply from node "<<m_node->GetId ()<<
+            "|| src: " << cache->GetDevice ()->GetAddress () << 
+            " / " << cache->GetInterface ()->GetAddress () <<
+            " || dst: " << toMac << " / " << toIp);
   arp.SetReply (cache->GetDevice ()->GetAddress (),
                 cache->GetInterface ()->GetAddress (),
                 toMac, toIp);
--- a/src/internet-node/arp-l3-protocol.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/arp-l3-protocol.h	Fri Sep 28 11:59:46 2007 +0100
@@ -23,9 +23,8 @@
 
 #include <list>
 #include "ns3/ipv4-address.h"
-#include "ns3/mac-address.h"
+#include "ns3/address.h"
 #include "ns3/ptr.h"
-#include "l3-protocol.h"
 
 namespace ns3 {
 
@@ -38,22 +37,21 @@
 /**
  * \brief An implementation of the ARP protocol
  */
-class ArpL3Protocol : public L3Protocol
+class ArpL3Protocol : public Object
 {
 public:
+  static const InterfaceId iid;
   static const uint16_t PROT_NUMBER;
   /**
    * \brief Constructor
    * \param node The node which this ARP object is associated with
    */
   ArpL3Protocol (Ptr<Node> node);
-  ~ArpL3Protocol ();
-
-  virtual TraceResolver *CreateTraceResolver (TraceContext const &context);
+  virtual ~ArpL3Protocol ();
   /**
    * \brief Recieve a packet
    */
-  virtual void Receive(Packet& p, Ptr<NetDevice> device);
+  void Receive(Ptr<NetDevice> device, const Packet& p, uint16_t protocol, const Address &from);
   /**
    * \brief Perform an ARP lookup
    * \param p
@@ -64,14 +62,14 @@
    */
   bool Lookup (Packet &p, Ipv4Address destination, 
 	       Ptr<NetDevice> device,
-	       MacAddress *hardwareDestination);
+	       Address *hardwareDestination);
 protected:
   virtual void DoDispose (void);
 private:
   typedef std::list<ArpCache *> CacheList;
   ArpCache *FindCache (Ptr<NetDevice> device);
   void SendArpRequest (ArpCache const *cache, Ipv4Address to);
-  void SendArpReply (ArpCache const *cache, Ipv4Address toIp, MacAddress toMac);
+  void SendArpReply (ArpCache const *cache, Ipv4Address toIp, Address toMac);
   CacheList m_cacheList;
   Ptr<Node> m_node;
 };
--- a/src/internet-node/arp-private.cc	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/* -*- 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
- * 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 "arp-private.h"
-#include "arp-l3-protocol.h"
-#include "ns3/assert.h"
-#include "ns3/net-device.h"
-
-namespace ns3 {
-
-const InterfaceId ArpPrivate::iid = MakeInterfaceId ("ArpPrivate", Object::iid);
-
-ArpPrivate::ArpPrivate (Ptr<ArpL3Protocol> arp)
-  : m_arp (arp)
-{
-  SetInterfaceId (ArpPrivate::iid);
-}
-ArpPrivate::~ArpPrivate ()
-{
-  NS_ASSERT (m_arp == 0);
-}
-
-bool 
-ArpPrivate::Lookup (Packet &p, Ipv4Address destination, 
-		     Ptr<NetDevice> device,
-		     MacAddress *hardwareDestination)
-{
-  return m_arp->Lookup (p, destination, device, hardwareDestination);
-}
-
-void
-ArpPrivate::DoDispose (void)
-{
-  m_arp = 0;
-  Object::DoDispose ();
-}
-
-
-} // namespace ns3
--- a/src/internet-node/arp-private.h	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/* -*- 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
- * 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 ARP_PRIVATE_H
-#define ARP_PRIVATE_H
-
-#include "ns3/object.h"
-#include "ns3/ipv4-address.h"
-
-namespace ns3 {
-
-class NetDevice;
-class MacAddress;
-class Packet;
-class ArpL3Protocol;
-
-class ArpPrivate : public Object
-{
-public:
-  static const InterfaceId iid;
-  ArpPrivate (Ptr<ArpL3Protocol> arp);
-  virtual ~ArpPrivate ();
-  bool Lookup (Packet &p, Ipv4Address destination, 
-	       Ptr<NetDevice> device,
-	       MacAddress *hardwareDestination);
-protected:
-  virtual void DoDispose (void);
-private:
-  Ptr<ArpL3Protocol> m_arp;
-};
-
-} // namespace ns3
-
-#endif /* ARP_PRIVATE_H */
--- a/src/internet-node/ascii-trace.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/ascii-trace.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -21,17 +21,11 @@
 #include "ascii-trace.h"
 
 #include "ns3/trace-context.h"
-#include "ns3/trace-root.h"
 #include "ns3/simulator.h"
 #include "ns3/node.h"
+#include "ns3/node-list.h"
+#include "ns3/packet.h"
 #include "ns3/queue.h"
-#include "ns3/node-list.h"
-#include "ns3/llc-snap-header.h"
-
-#include "ipv4-l3-protocol.h"
-#include "arp-header.h"
-#include "udp-header.h"
-#include "ipv4-header.h"
 
 namespace ns3 {
 
@@ -46,90 +40,64 @@
 void
 AsciiTrace::TraceAllQueues (void)
 {
-  TraceRoot::Connect ("/nodes/*/ipv4/interfaces/*/netdevice/queue/*",
-                      MakeCallback (&AsciiTrace::LogDevQueue, this));
+  Packet::EnableMetadata ();
+  NodeList::Connect ("/nodes/*/devices/*/queue/enqueue",
+                      MakeCallback (&AsciiTrace::LogDevQueueEnqueue, this));
+  NodeList::Connect ("/nodes/*/devices/*/queue/dequeue",
+                      MakeCallback (&AsciiTrace::LogDevQueueDequeue, this));
+  NodeList::Connect ("/nodes/*/devices/*/queue/drop",
+                      MakeCallback (&AsciiTrace::LogDevQueueDrop, this));
 }
 void
 AsciiTrace::TraceAllNetDeviceRx (void)
 {
-  TraceRoot::Connect ("/nodes/*/ipv4/interfaces/*/netdevice/rx",
-                      MakeCallback (&AsciiTrace::LogDevRx, this));
+  Packet::EnableMetadata ();
+  NodeList::Connect ("/nodes/*/devices/*/rx",
+                     MakeCallback (&AsciiTrace::LogDevRx, this));
+}
+
+void 
+AsciiTrace::LogDevQueueEnqueue (TraceContext const &context, 
+  Packet const &packet)
+{
+  m_os << "+ ";
+  m_os << Simulator::Now ().GetSeconds () << " ";
+  context.Print (m_os);
+  m_os << " pkt-uid=" << packet.GetUid () << " ";
+  packet.Print (m_os);
+  m_os << std::endl;
 }
 
-void
-AsciiTrace::PrintType (Packet const &packet)
+void 
+AsciiTrace::LogDevQueueDequeue (TraceContext const &context, 
+  Packet const &packet)
 {
-  Packet p = packet;
-  LlcSnapHeader llc;
-  p.RemoveHeader (llc);
-  switch (llc.GetType ())
-    {
-    case 0x0800: {
-      Ipv4Header ipv4;
-      p.RemoveHeader (ipv4);
-      if (ipv4.GetProtocol () == 17)
-        {
-          UdpHeader udp;
-          p.RemoveHeader (udp);
-          m_os << "udp size=" << p.GetSize ();
-        }
-    } break;
-    case 0x0806: {
-      ArpHeader arp;
-      p.RemoveHeader (arp);
-      m_os << "arp ";
-      if (arp.IsRequest ())
-        {
-          m_os << "request";
-        }
-      else
-        {
-          m_os << "reply ";
-        }
-    } break;
-    }
-} 
+  m_os << "- ";
+  m_os << Simulator::Now ().GetSeconds () << " ";
+  context.Print (m_os);
+  m_os << " pkt-uid=" << packet.GetUid () << " ";
+  packet.Print (m_os);
+  m_os << std::endl;
+}
 
 void 
-AsciiTrace::LogDevQueue (TraceContext const &context, Packet const &packet)
+AsciiTrace::LogDevQueueDrop (TraceContext const &context, 
+  Packet const &packet)
 {
-  enum Queue::TraceType type;
-  context.Get (type);
-  switch (type) 
-    {
-    case Queue::ENQUEUE:
-      m_os << "+ ";
-      break;
-    case Queue::DEQUEUE:
-      m_os << "- ";
-      break;
-    case Queue::DROP:
-      m_os << "d ";
-      break;
-    }
+  m_os << "d ";
   m_os << Simulator::Now ().GetSeconds () << " ";
-  NodeList::NodeIndex nodeIndex;
-  context.Get (nodeIndex);
-  m_os << "node=" << NodeList::GetNode (nodeIndex)->GetId () << " ";
-  Ipv4L3Protocol::InterfaceIndex interfaceIndex;
-  context.Get (interfaceIndex);
-  m_os << "interface=" << interfaceIndex << " ";
-  m_os << "pkt-uid=" << packet.GetUid () << " ";
-  PrintType (packet);
+  context.Print (m_os);
+  m_os << " pkt-uid=" << packet.GetUid () << " ";
+  packet.Print (m_os);
   m_os << std::endl;
 }
 void 
-AsciiTrace::LogDevRx (TraceContext const &context, Packet &p)
+AsciiTrace::LogDevRx (TraceContext const &context, const Packet &p)
 {
   m_os << "r " << Simulator::Now ().GetSeconds () << " ";
-  NodeList::NodeIndex nodeIndex;
-  context.Get (nodeIndex);
-  m_os << "node=" << NodeList::GetNode (nodeIndex)->GetId () << " ";
-  Ipv4L3Protocol::InterfaceIndex interfaceIndex;
-  context.Get (interfaceIndex);
-  m_os << "interface=" << interfaceIndex << " ";
-  m_os << "pkt-uid=" << p.GetUid () << " ";
-  PrintType (p);
+  context.Print (m_os);
+  m_os << " pkt-uid=" << p.GetUid () << " ";
+  p.Print (m_os);
   m_os << std::endl;  
 }
 
--- a/src/internet-node/ascii-trace.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/ascii-trace.h	Fri Sep 28 11:59:46 2007 +0100
@@ -37,9 +37,10 @@
   void TraceAllQueues (void);
   void TraceAllNetDeviceRx (void);
 private:
-  void PrintType (Packet const &p);
-  void LogDevQueue (TraceContext const &context, const Packet &p);
-  void LogDevRx (TraceContext const &context, Packet &p);
+  void LogDevQueueEnqueue (TraceContext const &context, const Packet &p);
+  void LogDevQueueDequeue (TraceContext const &context, const Packet &p);
+  void LogDevQueueDrop (TraceContext const &context, const Packet &p);
+  void LogDevRx (TraceContext const &context, const Packet &p);
   std::ofstream m_os;
 };
 
--- a/src/internet-node/header-utils.cc	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2006 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
- * 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 "header-utils.h"
-
-namespace ns3 {
-
-void WriteTo (Buffer::Iterator &i, Ipv4Address ad)
-{
-  i.WriteHtonU32 (ad.GetHostOrder ());
-}
-void WriteTo (Buffer::Iterator &i, MacAddress ad)
-{
-  uint8_t mac[MacAddress::MAX_LEN];
-  ad.Peek (mac);
-  i.Write (mac, ad.GetLength ());
-}
-
-void ReadFrom (Buffer::Iterator &i, Ipv4Address &ad)
-{
-  ad.SetHostOrder (i.ReadNtohU32 ());
-}
-void ReadFrom (Buffer::Iterator &i, MacAddress &ad, uint32_t len)
-{
-  uint8_t mac[MacAddress::MAX_LEN];
-  i.Read (mac, len);
-  ad.Set (mac, len);
-}
-
-
-
-}; // namespace ns3
--- a/src/internet-node/header-utils.h	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2006 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
- * 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 HEADER_UTILS_H
-#define HEADER_UTILS_H
-
-#include "ns3/buffer.h"
-#include "ns3/ipv4-address.h"
-#include "ns3/mac-address.h"
-
-namespace ns3 {
-
-void WriteTo (Buffer::Iterator &i, Ipv4Address ad);
-void WriteTo (Buffer::Iterator &i, MacAddress ad);
-
-void ReadFrom (Buffer::Iterator &i, Ipv4Address &ad);
-void ReadFrom (Buffer::Iterator &i, MacAddress &ad, uint32_t len);
-
-};
-
-#endif /* HEADER_UTILS_H */
--- a/src/internet-node/internet-node.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/internet-node.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -23,21 +23,18 @@
 
 #include "ns3/composite-trace-resolver.h"
 #include "ns3/net-device.h"
+#include "ns3/callback.h"
 
-#include "l3-demux.h"
 #include "ipv4-l4-demux.h"
 #include "internet-node.h"
 #include "udp-l4-protocol.h"
 #include "ipv4-l3-protocol.h"
 #include "arp-l3-protocol.h"
 #include "udp-impl.h"
-#include "arp-private.h"
 #include "ipv4-impl.h"
-#include "ipv4-private.h"
 
 namespace ns3 {
 
-
 InternetNode::InternetNode()
 {
   Construct ();
@@ -56,38 +53,34 @@
 {
   Ptr<Ipv4L3Protocol> ipv4 = Create<Ipv4L3Protocol> (this);
   Ptr<ArpL3Protocol> arp = Create<ArpL3Protocol> (this);
-  Ptr<UdpL4Protocol> udp = Create<UdpL4Protocol> (this);
+  // XXX remove the PeekPointer below.
+  RegisterProtocolHandler (MakeCallback (&Ipv4L3Protocol::Receive, PeekPointer (ipv4)), 
+                           Ipv4L3Protocol::PROT_NUMBER, 0);
+  RegisterProtocolHandler (MakeCallback (&ArpL3Protocol::Receive, PeekPointer (arp)),
+                           ArpL3Protocol::PROT_NUMBER, 0);
 
-  Ptr<L3Demux> l3Demux = Create<L3Demux> (this);
+
   Ptr<Ipv4L4Demux> ipv4L4Demux = Create<Ipv4L4Demux> (this);
-
-  l3Demux->Insert (ipv4);
-  l3Demux->Insert (arp);
+  Ptr<UdpL4Protocol> udp = Create<UdpL4Protocol> (this);
   ipv4L4Demux->Insert (udp);
 
   Ptr<UdpImpl> udpImpl = Create<UdpImpl> (udp);
-  Ptr<ArpPrivate> arpPrivate = Create<ArpPrivate> (arp);
   Ptr<Ipv4Impl> ipv4Impl = Create<Ipv4Impl> (ipv4);
-  Ptr<Ipv4Private> ipv4Private = Create<Ipv4Private> (ipv4);
 
-  Object::AddInterface (ipv4Private);
+  Object::AddInterface (ipv4);
+  Object::AddInterface (arp);
   Object::AddInterface (ipv4Impl);
-  Object::AddInterface (arpPrivate);
   Object::AddInterface (udpImpl);
-  Object::AddInterface (l3Demux);
   Object::AddInterface (ipv4L4Demux);
 }
 
-
-TraceResolver *
-InternetNode::DoCreateTraceResolver (TraceContext const &context)
+Ptr<TraceResolver>
+InternetNode::GetTraceResolver () const
 {
-  CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
-  Ptr<Ipv4Private> ipv4 = QueryInterface<Ipv4Private> (Ipv4Private::iid);
-  resolver->Add ("ipv4",
-                 MakeCallback (&Ipv4Private::CreateTraceResolver, PeekPointer (ipv4)),
-                 InternetNode::IPV4);
-
+  Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
+  Ptr<Ipv4L3Protocol> ipv4 = QueryInterface<Ipv4L3Protocol> (Ipv4L3Protocol::iid);
+  resolver->AddComposite ("ipv4", ipv4);
+  resolver->SetParentResolver (Node::GetTraceResolver ());
   return resolver;
 }
 
@@ -97,25 +90,4 @@
   Node::DoDispose ();
 }
 
-void 
-InternetNode::DoAddDevice (Ptr<NetDevice> device) const
-{
-  device->SetReceiveCallback (MakeCallback (&InternetNode::ReceiveFromDevice, this));
-}
-
-bool
-InternetNode::ReceiveFromDevice (Ptr<NetDevice> device, const Packet &p, uint16_t protocolNumber) const
-{
-  Ptr<L3Demux> demux = QueryInterface<L3Demux> (L3Demux::iid);
-  Ptr<L3Protocol> target = demux->GetProtocol (protocolNumber);
-  if (target != 0) 
-    {
-      Packet packet = p;
-      target->Receive(packet, device);
-      return true;
-    }
-  return false;
-}
-
-
 }//namespace ns3
--- a/src/internet-node/internet-node.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/internet-node.h	Fri Sep 28 11:59:46 2007 +0100
@@ -36,18 +36,14 @@
 class InternetNode : public Node 
 {
 public:
-  enum TraceType {
-    IPV4,
-  };
   InternetNode();
   InternetNode(uint32_t systemId);
   virtual ~InternetNode ();
 
 protected:
   virtual void DoDispose(void);
+  virtual Ptr<TraceResolver> GetTraceResolver (void) const;
 private:
-  virtual void DoAddDevice (Ptr<NetDevice> device) const;
-  virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context);
   bool ReceiveFromDevice (Ptr<NetDevice> device, const Packet &p, uint16_t protocolNumber) const;
   void Construct (void);
 };
--- a/src/internet-node/ipv4-end-point-demux.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/ipv4-end-point-demux.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -21,15 +21,21 @@
 
 #include "ipv4-end-point-demux.h"
 #include "ipv4-end-point.h"
+#include "ns3/log.h"
 
 namespace ns3{
 
+NS_LOG_COMPONENT_DEFINE ("Ipv4EndPointDemux");
+
 Ipv4EndPointDemux::Ipv4EndPointDemux ()
-  : m_ephemeral (1025)
-{}
+  : m_ephemeral (49152)
+{
+  NS_LOG_FUNCTION;
+}
 
 Ipv4EndPointDemux::~Ipv4EndPointDemux ()
 {
+  NS_LOG_FUNCTION;
   for (EndPointsI i = m_endPoints.begin (); i != m_endPoints.end (); i++) 
     {
       Ipv4EndPoint *endPoint = *i;
@@ -41,6 +47,7 @@
 bool
 Ipv4EndPointDemux::LookupPortLocal (uint16_t port)
 {
+  NS_LOG_FUNCTION;
   for (EndPointsI i = m_endPoints.begin (); i != m_endPoints.end (); i++) 
     {
       if ((*i)->GetLocalPort  () == port) 
@@ -54,6 +61,7 @@
 bool
 Ipv4EndPointDemux::LookupLocal (Ipv4Address addr, uint16_t port)
 {
+  NS_LOG_FUNCTION;
   for (EndPointsI i = m_endPoints.begin (); i != m_endPoints.end (); i++) 
     {
       if ((*i)->GetLocalPort () == port &&
@@ -68,41 +76,56 @@
 Ipv4EndPoint *
 Ipv4EndPointDemux::Allocate (void)
 {
+  NS_LOG_FUNCTION;
   uint16_t port = AllocateEphemeralPort ();
   if (port == 0) 
     {
+      NS_LOG_WARN ("Ephemeral port allocation failed.");
       return 0;
     }
   Ipv4EndPoint *endPoint = new Ipv4EndPoint (Ipv4Address::GetAny (), port);
   m_endPoints.push_back (endPoint);
+  NS_LOG_DEBUG ("Now have >>" << m_endPoints.size () << "<< endpoints.");
   return endPoint;
 }
+
 Ipv4EndPoint *
 Ipv4EndPointDemux::Allocate (Ipv4Address address)
 {
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << this << ", " << address << ")");
   uint16_t port = AllocateEphemeralPort ();
   if (port == 0) 
     {
+      NS_LOG_WARN ("Ephemeral port allocation failed.");
       return 0;
     }
   Ipv4EndPoint *endPoint = new Ipv4EndPoint (address, port);
   m_endPoints.push_back (endPoint);
+  NS_LOG_DEBUG ("Now have >>" << m_endPoints.size () << "<< endpoints.");
   return endPoint;
 }
+
 Ipv4EndPoint *
 Ipv4EndPointDemux::Allocate (uint16_t port)
 {
+  NS_LOG_FUNCTION;
   return Allocate (Ipv4Address::GetAny (), port);
 }
+
 Ipv4EndPoint *
 Ipv4EndPointDemux::Allocate (Ipv4Address address, uint16_t port)
 {
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << this << ", " << address << ", " << port << ")");
   if (LookupLocal (address, port)) 
     {
+      NS_LOG_WARN ("Duplicate address/port; failing.");
       return 0;
     }
   Ipv4EndPoint *endPoint = new Ipv4EndPoint (address, port);
   m_endPoints.push_back (endPoint);
+  NS_LOG_DEBUG ("Now have >>" << m_endPoints.size () << "<< endpoints.");
   return endPoint;
 }
 
@@ -110,6 +133,11 @@
 Ipv4EndPointDemux::Allocate (Ipv4Address localAddress, uint16_t localPort,
 			     Ipv4Address peerAddress, uint16_t peerPort)
 {
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(localAddress=" << localAddress
+    << ", localPort=" << localPort
+    << ", peerAddress=" << peerAddress
+    << ", peerPort=" << peerPort << ")");
   for (EndPointsI i = m_endPoints.begin (); i != m_endPoints.end (); i++) 
     {
       if ((*i)->GetLocalPort () == localPort &&
@@ -117,6 +145,7 @@
           (*i)->GetPeerPort () == peerPort &&
           (*i)->GetPeerAddress () == peerAddress) 
         {
+          NS_LOG_WARN ("No way we can allocate this end-point.");
           /* no way we can allocate this end-point. */
           return 0;
         }
@@ -124,12 +153,16 @@
   Ipv4EndPoint *endPoint = new Ipv4EndPoint (localAddress, localPort);
   endPoint->SetPeer (peerAddress, peerPort);
   m_endPoints.push_back (endPoint);
+
+  NS_LOG_DEBUG ("Now have >>" << m_endPoints.size () << "<< endpoints.");
+
   return endPoint;
 }
 
 void 
 Ipv4EndPointDemux::DeAllocate (Ipv4EndPoint *endPoint)
 {
+  NS_LOG_FUNCTION;
   for (EndPointsI i = m_endPoints.begin (); i != m_endPoints.end (); i++) 
     {
       if (*i == endPoint)
@@ -141,41 +174,58 @@
     }
 }
 
-
 /*
  * If we have an exact match, we return it.
  * Otherwise, if we find a generic match, we return it.
  * Otherwise, we return 0.
  */
-Ipv4EndPoint *
+Ipv4EndPointDemux::EndPoints
 Ipv4EndPointDemux::Lookup (Ipv4Address daddr, uint16_t dport, 
-                              Ipv4Address saddr, uint16_t sport)
+                           Ipv4Address saddr, uint16_t sport,
+                           Ptr<Ipv4Interface> incomingInterface)
 {
+  NS_LOG_FUNCTION;
   uint32_t genericity = 3;
   Ipv4EndPoint *generic = 0;
-  //TRACE ("lookup " << daddr << ":" << dport << " " << saddr << ":" << sport);
+  EndPoints retval;
+
+  NS_LOG_PARAM ("(daddr=" << daddr << ", dport=" << dport
+    << ", saddr=" << saddr << ", sport=" << sport << ")");
+
   for (EndPointsI i = m_endPoints.begin (); i != m_endPoints.end (); i++) 
     {
-#if 0
-      TRACE ("against " << 
-             (*i)->GetLocalAddress ()
-             << ":" << 
-             (*i)->GetLocalPort () 
-             << " " << 
-             (*i)->GetPeerAddress () 
-             << ":" 
-             << (*i)->GetPeerPort ());
-#endif
+      NS_LOG_DEBUG ("Looking at endpoint dport=" << (*i)->GetLocalPort ()
+                    << " daddr=" << (*i)->GetLocalAddress ()
+                    << " sport=" << (*i)->GetPeerPort ()
+                    << " saddr=" << (*i)->GetPeerAddress ());
       if ((*i)->GetLocalPort () != dport) 
         {
+          NS_LOG_LOGIC ("Skipping endpoint " << &(*i)
+                        << " because endpoint dport "
+                        << (*i)->GetLocalPort ()
+                        << " does not match packet dport " << dport);
           continue;
         }
-      if ((*i)->GetLocalAddress () == daddr &&
-          (*i)->GetPeerPort () == sport &&
-          (*i)->GetPeerAddress () == saddr) 
+      bool isBroadcast = 
+        (daddr.IsBroadcast () ||
+         daddr.IsSubnetDirectedBroadcast (incomingInterface->GetNetworkMask ()));
+      NS_LOG_DEBUG ("dest addr " << daddr << " broadcast? " << isBroadcast);
+
+      NS_LOG_LOGIC ("Local address matches: " << 
+        bool ((*i)->GetLocalAddress () == daddr || isBroadcast));
+      NS_LOG_LOGIC ("Peer port matches: " << 
+        bool ((*i)->GetPeerPort () == sport || (*i)->GetPeerPort () == 0));
+      NS_LOG_LOGIC ("Peer address matches: " << 
+        bool ((*i)->GetPeerAddress () == saddr ||
+        (*i)->GetPeerAddress () == Ipv4Address::GetAny ()));
+      
+      if ( ((*i)->GetLocalAddress () == daddr || isBroadcast)
+           && ((*i)->GetPeerPort () == sport || (*i)->GetPeerPort () == 0)
+           && ((*i)->GetPeerAddress () == saddr || (*i)->GetPeerAddress () == Ipv4Address::GetAny ()))
         {
+          NS_LOG_LOGIC ("MATCH");
           /* this is an exact match. */
-          return *i;
+          retval.push_back (*i);
         }
       uint32_t tmp = 0;
       if ((*i)->GetLocalAddress () == Ipv4Address::GetAny ()) 
@@ -192,19 +242,24 @@
           genericity = tmp;
         }
     }
-  return generic;
+  if (retval.size () == 0 && generic != 0)
+    {
+      retval.push_back (generic);
+    }
+  return retval;
 }
 
 uint16_t
 Ipv4EndPointDemux::AllocateEphemeralPort (void)
 {
+  NS_LOG_FUNCTION;
   uint16_t port = m_ephemeral;
   do 
     {
       port++;
-      if (port > 5000) 
+      if (port == 65535) 
         {
-          port = 1024;
+          port = 49152;
         }
       if (!LookupPortLocal (port)) 
         {
--- a/src/internet-node/ipv4-end-point-demux.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/ipv4-end-point-demux.h	Fri Sep 28 11:59:46 2007 +0100
@@ -25,6 +25,7 @@
 #include <stdint.h>
 #include <list>
 #include "ns3/ipv4-address.h"
+#include "ipv4-interface.h"
 
 namespace ns3 {
 
@@ -32,15 +33,19 @@
 
 class Ipv4EndPointDemux {
 public:
+  typedef std::list<Ipv4EndPoint *> EndPoints;
+  typedef std::list<Ipv4EndPoint *>::iterator EndPointsI;
+
   Ipv4EndPointDemux ();
   ~Ipv4EndPointDemux ();
 
   bool LookupPortLocal (uint16_t port);
   bool LookupLocal (Ipv4Address addr, uint16_t port);
-  Ipv4EndPoint *Lookup (Ipv4Address daddr, 
-                        uint16_t dport, 
-                        Ipv4Address saddr, 
-                        uint16_t sport);
+  EndPoints Lookup (Ipv4Address daddr, 
+                    uint16_t dport, 
+                    Ipv4Address saddr, 
+                    uint16_t sport,
+                    Ptr<Ipv4Interface> incomingInterface);
 
   Ipv4EndPoint *Allocate (void);
   Ipv4EndPoint *Allocate (Ipv4Address address);
@@ -55,8 +60,6 @@
 
  private:
   uint16_t AllocateEphemeralPort (void);
-  typedef std::list<Ipv4EndPoint *> EndPoints;
-  typedef std::list<Ipv4EndPoint *>::iterator EndPointsI;
 
   uint16_t m_ephemeral;
   EndPoints m_endPoints;
--- a/src/internet-node/ipv4-end-point.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/ipv4-end-point.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -42,6 +42,13 @@
 {
   return m_localAddr;
 }
+
+void 
+Ipv4EndPoint::SetLocalAddress (Ipv4Address address)
+{
+  m_localAddr = address;
+}
+
 uint16_t 
 Ipv4EndPoint::GetLocalPort (void)
 {
--- a/src/internet-node/ipv4-end-point.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/ipv4-end-point.h	Fri Sep 28 11:59:46 2007 +0100
@@ -37,6 +37,7 @@
   ~Ipv4EndPoint ();
 
   Ipv4Address GetLocalAddress (void);
+  void SetLocalAddress (Ipv4Address address);
   uint16_t GetLocalPort (void);
   Ipv4Address GetPeerAddress (void);
   uint16_t GetPeerPort (void);
--- a/src/internet-node/ipv4-header.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/ipv4-header.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -20,27 +20,25 @@
  */
 
 #include "ns3/assert.h"
-#include "ns3/debug.h"
+#include "ns3/log.h"
 #include "ns3/header.h"
 #include "ipv4-header.h"
 
-NS_DEBUG_COMPONENT_DEFINE ("Ipv4Header");
+NS_LOG_COMPONENT_DEFINE ("Ipv4Header");
 
 namespace ns3 {
 
-static uint16_t 
-UtilsNtoh16 (uint16_t v)
-{
-  uint16_t val;
-  uint8_t *array;
-  array = (uint8_t *)&v;
-  val = (array[0] << 8) | (array[1] << 0);
-  return val;
-}
-
+NS_HEADER_ENSURE_REGISTERED (Ipv4Header);
 
 bool Ipv4Header::m_calcChecksum = false;
 
+uint32_t
+Ipv4Header::GetUid (void)
+{
+  static uint32_t uid = AllocateUid<Ipv4Header> ("Ipv4Header.ns3");
+  return uid;
+}
+
 Ipv4Header::Ipv4Header ()
   : m_payloadSize (0),
     m_identification (0),
@@ -51,8 +49,6 @@
     m_fragmentOffset (0),
     m_goodChecksum (true)
 {}
-Ipv4Header::~Ipv4Header ()
-{}
 
 void 
 Ipv4Header::EnableChecksums (void)
@@ -190,21 +186,48 @@
   return m_goodChecksum;
 }
 
+std::string 
+Ipv4Header::GetName (void) const
+{
+  return "IPV4";
+}
+
 void 
-Ipv4Header::PrintTo (std::ostream &os) const
+Ipv4Header::Print (std::ostream &os) const
 {
   // ipv4, right ?
-  os << "(ipv4)"
-     << " tos=" << (uint32_t)m_tos
-     << ", payload length=" << UtilsNtoh16 (m_payloadSize)
-     << ", id=" << m_identification
-     << ", " << (IsLastFragment ()?"last":"more")
-     << ", " << (IsDontFragment ()?"dont":"may")
-     << ", frag offset=" << m_fragmentOffset
-     << ", ttl=" << m_ttl
-     << ", protocol=" << m_protocol
-     << ", source=" << m_source
-     << ", destination=" << m_destination;
+  std::string flags;
+  if (m_flags == 0)
+    {
+      flags = "none";
+    }
+  else if (m_flags & MORE_FRAGMENTS &&
+           m_flags & DONT_FRAGMENT)
+    {
+      flags = "MF|DF";
+    }
+  else if (m_flags & DONT_FRAGMENT)
+    {
+      flags = "DF";
+    }
+  else if (m_flags & MORE_FRAGMENTS)
+    {
+      flags = "MF";
+    }
+  else
+    {
+      flags = "XX";
+    }
+  os << "("
+     << "tos 0x" << std::hex << m_tos << std::dec << " "
+     << "ttl " << m_ttl << " "
+     << "id " << m_identification << " "
+     << "offset " << m_fragmentOffset << " "
+     << "flags [" << flags << "] "
+     << "length: " << (m_payloadSize + 5 * 4)
+     << ") "
+     << m_source << " > " << m_destination
+    ;
 }
 uint32_t 
 Ipv4Header::GetSerializedSize (void) const
@@ -213,7 +236,7 @@
 }
 
 void
-Ipv4Header::SerializeTo (Buffer::Iterator start) const
+Ipv4Header::Serialize (Buffer::Iterator start) const
 {
   Buffer::Iterator i = start;
   
@@ -248,7 +271,7 @@
       uint8_t *data = start.PeekData ();
       uint16_t checksum = UtilsChecksumCalculate (0, data, GetSize ());
       checksum = UtilsChecksumComplete (checksum);
-      NS_DEBUG ("checksum=" <<checksum);
+      NS_LOG_LOGIC ("checksum=" <<checksum);
       i = start;
       i.Next (10);
       i.WriteU16 (checksum);
@@ -256,7 +279,7 @@
     }
 }
 uint32_t
-Ipv4Header::DeserializeFrom (Buffer::Iterator start)
+Ipv4Header::Deserialize (Buffer::Iterator start)
 {
   Buffer::Iterator i = start;
   uint8_t verIhl = i.ReadU8 ();
--- a/src/internet-node/ipv4-header.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/ipv4-header.h	Fri Sep 28 11:59:46 2007 +0100
@@ -29,13 +29,14 @@
 /**
  * \brief Packet header for IPv4
  */
-class Ipv4Header : public Header {
+class Ipv4Header : public Header 
+{
 public:
+  static uint32_t GetUid (void);
   /**
    * \brief Construct a null IPv4 header
    */
   Ipv4Header ();
-  virtual ~Ipv4Header ();
   /**
    * \brief Enable checksum calculation for IP (XXX currently has no effect)
    */
@@ -139,11 +140,12 @@
    */
   bool IsChecksumOk (void) const;
 
+  std::string GetName (void) const;
+  void Print (std::ostream &os) const;
+  uint32_t GetSerializedSize (void) const;
+  void Serialize (Buffer::Iterator start) const;
+  uint32_t Deserialize (Buffer::Iterator start);
 private:
-  virtual void PrintTo (std::ostream &os) const;
-  virtual uint32_t GetSerializedSize (void) const;
-  virtual void SerializeTo (Buffer::Iterator start) const;
-  virtual uint32_t DeserializeFrom (Buffer::Iterator start);
 
   enum FlagsE {
     DONT_FRAGMENT = (1<<0),
@@ -164,7 +166,7 @@
   bool m_goodChecksum;
 };
 
-}; // namespace ns3
+} // namespace ns3
 
 
 #endif /* IPV4_HEADER_H */
--- a/src/internet-node/ipv4-impl.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/ipv4-impl.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -39,6 +39,13 @@
   m_ipv4 = 0;
 }
 
+void
+Ipv4Impl::AddRoutingProtocol (Ptr<Ipv4RoutingProtocol> routingProtocol,
+                              int16_t priority)
+{
+  m_ipv4->AddRoutingProtocol (routingProtocol, priority);
+}
+
 void 
 Ipv4Impl::AddHostRouteTo (Ipv4Address dest, 
 			   Ipv4Address nextHop, 
@@ -88,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)
 {
@@ -105,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);
@@ -119,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	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/ipv4-impl.h	Fri Sep 28 11:59:46 2007 +0100
@@ -35,6 +35,9 @@
 
   virtual ~Ipv4Impl ();
 
+  virtual void AddRoutingProtocol (Ptr<Ipv4RoutingProtocol> routingProtocol,
+                                   int16_t priority);
+
   virtual void AddHostRouteTo (Ipv4Address dest, 
 			       Ipv4Address nextHop, 
 			       uint32_t interface);
@@ -52,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	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/ipv4-interface.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -22,6 +22,10 @@
 #include "ipv4-interface.h"
 #include "ns3/ipv4-address.h"
 #include "ns3/net-device.h"
+#include "ns3/trace-resolver.h"
+#include "ns3/log.h"
+
+NS_LOG_COMPONENT_DEFINE ("Ipv4Interface");
 
 namespace ns3 {
 
@@ -34,56 +38,75 @@
 Ipv4Interface::Ipv4Interface (Ptr<NetDevice> nd) 
   : m_netdevice (nd), 
     m_ifup(false)
-{}
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << &nd << ")");
+}
 
 Ipv4Interface::~Ipv4Interface ()
-{}
+{
+  NS_LOG_FUNCTION;
+}
+
+void
+Ipv4Interface::DoDispose (void)
+{
+  NS_LOG_FUNCTION;
+  m_netdevice = 0;
+  Object::DoDispose ();
+}
 
 Ptr<NetDevice>
 Ipv4Interface::GetDevice (void) const
 {
+  NS_LOG_FUNCTION;
   return m_netdevice;
 }
 
-TraceResolver *
-Ipv4Interface::CreateTraceResolver (TraceContext const &context)
-{
-  return DoCreateTraceResolver (context);
-}
-
 void 
 Ipv4Interface::SetAddress (Ipv4Address a)
 {
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << a << ")");
   m_address = a;
 }
+
 void 
 Ipv4Interface::SetNetworkMask (Ipv4Mask mask)
 {
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << mask << ")");
   m_netmask = mask;
 }
 
 Ipv4Address
 Ipv4Interface::GetBroadcast (void) const
 {
+  NS_LOG_FUNCTION;
   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_LOG_FUNCTION;
   return m_netmask;
 }
+
 Ipv4Address 
 Ipv4Interface::GetAddress (void) const
 {
+  NS_LOG_FUNCTION;
   return m_address;
 }
 
 uint16_t 
 Ipv4Interface::GetMtu (void) const
 {
+  NS_LOG_FUNCTION;
   if (m_netdevice == 0)
     {
       uint32_t mtu = (1<<16) - 1;
@@ -92,32 +115,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_LOG_FUNCTION;
   return m_ifup;
 }
 
 bool 
 Ipv4Interface::IsDown (void) const
 {
+  NS_LOG_FUNCTION;
   return !m_ifup;
 }
 
 void 
 Ipv4Interface::SetUp (void)
 {
+  NS_LOG_FUNCTION;
   m_ifup = true;
 }
 
 void 
 Ipv4Interface::SetDown (void)
 {
+  NS_LOG_FUNCTION;
   m_ifup = false;
 }
 
@@ -125,7 +152,9 @@
 void 
 Ipv4Interface::Send(Packet p, Ipv4Address dest)
 {
+  NS_LOG_FUNCTION;
   if (IsUp()) {
+    NS_LOG_LOGIC ("SendTo");
     SendTo(p, dest);
   }
 }
--- a/src/internet-node/ipv4-interface.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/ipv4-interface.h	Fri Sep 28 11:59:46 2007 +0100
@@ -26,6 +26,7 @@
 #include <list>
 #include "ns3/ipv4-address.h"
 #include "ns3/ptr.h"
+#include "ns3/object.h"
 
 namespace ns3 {
 
@@ -60,9 +61,8 @@
  *
  * Subclasses must implement the two methods:
  *   - Ipv4Interface::SendTo
- *   - Ipv4Interface::DoCreateTraceResolver
  */
-class Ipv4Interface 
+class Ipv4Interface  : public Object
 {
 public:
   /**
@@ -74,17 +74,6 @@
   virtual ~Ipv4Interface();
 
   /**
-   * \param context the trace context to use to construct the
-   *        TraceResolver to return
-   * \returns a TraceResolver which can resolve all traces
-   *          performed in this object. The caller must
-   *          delete the returned object.
-   *
-   * This method will delegate the work to the private DoCreateTraceResolver 
-   * method which is supposed to be implemented by subclasses.
-   */
-  TraceResolver *CreateTraceResolver (TraceContext const &context);
-  /**
    * \returns the underlying NetDevice. This method can return
    *          zero if this interface has no associated NetDevice.
    */
@@ -150,10 +139,10 @@
    */ 
   void Send(Packet p, Ipv4Address dest);
 
-
- private:
+protected:
+  virtual void DoDispose (void);
+private:
   virtual void SendTo (Packet p, Ipv4Address dest) = 0;
-  virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context) = 0;
   Ptr<NetDevice> m_netdevice;
   bool m_ifup;
   Ipv4Address m_address;
--- a/src/internet-node/ipv4-l3-protocol.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/ipv4-l3-protocol.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -20,9 +20,8 @@
 //
 
 #include "ns3/packet.h"
-#include "ns3/debug.h"
+#include "ns3/log.h"
 #include "ns3/composite-trace-resolver.h"
-#include "ns3/array-trace-resolver.h"
 #include "ns3/callback.h"
 #include "ns3/ipv4-address.h"
 #include "ns3/ipv4-route.h"
@@ -37,58 +36,156 @@
 #include "arp-ipv4-interface.h"
 #include "ipv4-l4-demux.h"
 
-NS_DEBUG_COMPONENT_DEFINE ("Ipv4L3Protocol");
+NS_LOG_COMPONENT_DEFINE ("Ipv4L3Protocol");
 
 namespace ns3 {
 
+const InterfaceId Ipv4L3Protocol::iid = MakeInterfaceId ("Ipv4L3Protocol", Object::iid);
 const uint16_t Ipv4L3Protocol::PROT_NUMBER = 0x0800;
 
+Ipv4L3ProtocolTraceContextElement::Ipv4L3ProtocolTraceContextElement ()
+  : m_type (TX)
+{
+  NS_LOG_FUNCTION;
+}
+
+Ipv4L3ProtocolTraceContextElement::Ipv4L3ProtocolTraceContextElement (enum Type type)
+  : m_type (type)
+{
+  NS_LOG_FUNCTION;
+}
+
+bool 
+Ipv4L3ProtocolTraceContextElement::IsTx (void) const
+{
+  NS_LOG_FUNCTION;
+  return m_type == TX;
+}
+
+bool 
+Ipv4L3ProtocolTraceContextElement::IsRx (void) const
+{
+  NS_LOG_FUNCTION;
+  return m_type == RX;
+}
+
+bool 
+Ipv4L3ProtocolTraceContextElement::IsDrop (void) const
+{
+  NS_LOG_FUNCTION;
+  return m_type == DROP;
+}
+
+void 
+Ipv4L3ProtocolTraceContextElement::Print (std::ostream &os) const
+{
+  NS_LOG_FUNCTION;
+  os << "ipv4=";
+  switch (m_type)
+    {
+    case TX:
+      os << "tx";
+      break;
+    case RX:
+      os << "rx";
+      break;
+    case DROP:
+      os << "drop";
+      break;
+    }
+}
+
+uint16_t 
+Ipv4L3ProtocolTraceContextElement::GetUid (void)
+{
+  NS_LOG_FUNCTION;
+  static uint16_t uid = AllocateUid<Ipv4L3ProtocolTraceContextElement> ("Ipv4L3ProtocolTraceContextElement");
+  return uid;
+}
+
+std::string 
+Ipv4L3ProtocolTraceContextElement::GetTypeName (void) const
+{
+  NS_LOG_FUNCTION;
+  return "ns3::Ipv4L3ProtocolTraceContextElement";
+}
+
+Ipv4L3ProtocolInterfaceIndex::Ipv4L3ProtocolInterfaceIndex ()
+  : m_index (0)
+{
+  NS_LOG_FUNCTION;
+}
+
+Ipv4L3ProtocolInterfaceIndex::Ipv4L3ProtocolInterfaceIndex (uint32_t index)
+  : m_index (index)
+{
+  NS_LOG_FUNCTION;
+}
+
+uint32_t 
+Ipv4L3ProtocolInterfaceIndex::Get (void) const
+{
+  NS_LOG_FUNCTION;
+  return m_index;
+}
+
+void 
+Ipv4L3ProtocolInterfaceIndex::Print (std::ostream &os) const
+{
+  os << "ipv4-interface=" << m_index;
+}
+
+uint16_t 
+Ipv4L3ProtocolInterfaceIndex::GetUid (void)
+{
+  NS_LOG_FUNCTION;
+  static uint16_t uid = AllocateUid<Ipv4L3ProtocolInterfaceIndex> ("Ipv4L3ProtocolInterfaceIndex");
+  return uid;
+}
+
+std::string
+Ipv4L3ProtocolInterfaceIndex::GetTypeName (void) const
+{
+  NS_LOG_FUNCTION;
+  return "ns3::Ipv4L3ProtocolInterfaceIndex";
+}
+
+
 Ipv4L3Protocol::Ipv4L3Protocol(Ptr<Node> node)
-  : L3Protocol (PROT_NUMBER, 4),
-    m_nInterfaces (0),
+  : m_nInterfaces (0),
     m_defaultTtl (64),
     m_identification (0),
-    m_defaultRoute (0),
     m_node (node)
 {
+  NS_LOG_FUNCTION;
+  SetInterfaceId (Ipv4L3Protocol::iid);
+  m_staticRouting = Create<Ipv4StaticRouting> ();
+  AddRoutingProtocol (m_staticRouting, 0);
   SetupLoopback ();
 }
+
 Ipv4L3Protocol::~Ipv4L3Protocol ()
-{}
+{
+  NS_LOG_FUNCTION;
+}
 
 void 
 Ipv4L3Protocol::DoDispose (void)
 {
-  for (Ipv4InterfaceList::iterator i = m_interfaces.begin (); i != m_interfaces.end (); i++)
-    {
-      delete (*i);
-    }
+  NS_LOG_FUNCTION;
   m_interfaces.clear ();
-  for (HostRoutesI i = m_hostRoutes.begin (); 
-       i != m_hostRoutes.end (); 
-       i = m_hostRoutes.erase (i)) 
-    {
-      delete (*i);
-    }
-  for (NetworkRoutesI j = m_networkRoutes.begin (); 
-       j != m_networkRoutes.end (); 
-       j = m_networkRoutes.erase (j)) 
-    {
-      delete (*j);
-    }
-  if (m_defaultRoute != 0)
-    {
-      delete m_defaultRoute;
-      m_defaultRoute = 0;
-    }
   m_node = 0;
-  L3Protocol::DoDispose ();
+  m_staticRouting->Dispose ();
+  m_staticRouting = 0;
+  Object::DoDispose ();
 }
 
 void
 Ipv4L3Protocol::SetupLoopback (void)
 {
-  Ipv4LoopbackInterface * interface = new Ipv4LoopbackInterface (m_node);
+  NS_LOG_FUNCTION;
+
+  Ptr<Ipv4LoopbackInterface> interface = Create<Ipv4LoopbackInterface> (m_node);
   interface->SetAddress (Ipv4Address::GetLoopback ());
   interface->SetNetworkMask (Ipv4Mask::GetLoopback ());
   uint32_t index = AddIpv4Interface (interface);
@@ -96,33 +193,36 @@
   interface->SetUp ();
 }
 
-TraceResolver *
-Ipv4L3Protocol::CreateTraceResolver (TraceContext const &context)
+Ptr<TraceResolver>
+Ipv4L3Protocol::GetTraceResolver (void) const
 {
-  CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
-  resolver->Add ("tx", m_txTrace, Ipv4L3Protocol::TX);
-  resolver->Add ("rx", m_rxTrace, Ipv4L3Protocol::RX);
-  resolver->Add ("drop", m_dropTrace, Ipv4L3Protocol::DROP);
-  resolver->Add ("interfaces", 
-                 MakeCallback (&Ipv4L3Protocol::InterfacesCreateTraceResolver, this), 
-                 Ipv4L3Protocol::INTERFACES);
-  return resolver;
-}
+  NS_LOG_FUNCTION;
 
-TraceResolver *
-Ipv4L3Protocol::InterfacesCreateTraceResolver (TraceContext const &context) const
-{
-  ArrayTraceResolver<Ipv4Interface> *resolver = 
-    new ArrayTraceResolver<Ipv4Interface> 
-    (context,
-     MakeCallback (&Ipv4L3Protocol::GetNInterfaces, this),
-     MakeCallback (&Ipv4L3Protocol::GetInterface, this));
+  Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
+  resolver->AddSource ("tx", 
+                       TraceDoc ("send ipv4 packet to outgoing interface",
+                                 "const Packet &", "packet sent",
+                                 "uint32_t", "index of output ipv4 interface"),
+                       m_txTrace, Ipv4L3ProtocolTraceContextElement(Ipv4L3ProtocolTraceContextElement::TX));
+  resolver->AddSource ("rx",
+                       TraceDoc ("receive ipv4 packet from incoming interface",
+                                 "const Packet &", "packet received",
+                                 "uint32_t", "index of input ipv4 interface"),
+                       m_rxTrace, Ipv4L3ProtocolTraceContextElement(Ipv4L3ProtocolTraceContextElement::RX));
+  resolver->AddSource ("drop", 
+                       TraceDoc ("drop ipv4 packet",
+                                 "const Packet &", "packet dropped"),
+                       m_dropTrace, Ipv4L3ProtocolTraceContextElement (Ipv4L3ProtocolTraceContextElement::DROP));
+  resolver->AddArray ("interfaces", 
+                      m_interfaces.begin (), m_interfaces.end (), 
+                      Ipv4L3ProtocolInterfaceIndex ());
   return resolver;
 }
 
 void 
 Ipv4L3Protocol::SetDefaultTtl (uint8_t ttl)
 {
+  NS_LOG_FUNCTION;
   m_defaultTtl = ttl;
 }
     
@@ -132,201 +232,232 @@
                       Ipv4Address nextHop, 
                       uint32_t interface)
 {
-  Ipv4Route *route = new Ipv4Route ();
-  *route = Ipv4Route::CreateHostRouteTo (dest, nextHop, interface);
-  m_hostRoutes.push_back (route);
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << dest << ", " << nextHop << ", " << interface << ")");
+  m_staticRouting->AddHostRouteTo (dest, nextHop, interface);
 }
+
 void 
 Ipv4L3Protocol::AddHostRouteTo (Ipv4Address dest, 
 				uint32_t interface)
 {
-  Ipv4Route *route = new Ipv4Route ();
-  *route = Ipv4Route::CreateHostRouteTo (dest, interface);
-  m_hostRoutes.push_back (route);
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << dest << ", " << interface << ")");
+  m_staticRouting->AddHostRouteTo (dest, interface);
 }
+
 void 
 Ipv4L3Protocol::AddNetworkRouteTo (Ipv4Address network, 
 				   Ipv4Mask networkMask, 
 				   Ipv4Address nextHop, 
 				   uint32_t interface)
 {
-  Ipv4Route *route = new Ipv4Route ();
-  *route = Ipv4Route::CreateNetworkRouteTo (network,
-                                            networkMask,
-                                            nextHop,
-                                            interface);
-  m_networkRoutes.push_back (route);
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << network << ", " << networkMask << ", " << nextHop << 
+    ", " << interface << ")");
+  m_staticRouting->AddNetworkRouteTo (network, networkMask, nextHop, interface);
 }
+
 void 
 Ipv4L3Protocol::AddNetworkRouteTo (Ipv4Address network, 
 				   Ipv4Mask networkMask, 
 				   uint32_t interface)
 {
-  Ipv4Route *route = new Ipv4Route ();
-  *route = Ipv4Route::CreateNetworkRouteTo (network,
-                                            networkMask,
-                                            interface);
-  m_networkRoutes.push_back (route);
+  NS_LOG_FUNCTION; 
+  NS_LOG_PARAM ("(" << network << ", " << networkMask << ", " << interface << 
+    ")");
+  m_staticRouting->AddNetworkRouteTo (network, networkMask, interface);
 }
+
 void 
 Ipv4L3Protocol::SetDefaultRoute (Ipv4Address nextHop, 
 				 uint32_t interface)
 {
-  Ipv4Route *route = new Ipv4Route ();
-  *route = Ipv4Route::CreateDefaultRoute (nextHop, interface);
-  delete m_defaultRoute;
-  m_defaultRoute = route;
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << nextHop << ", " << interface << ")");
+  m_staticRouting->SetDefaultRoute (nextHop, interface);
+}
+
+void
+Ipv4L3Protocol::Lookup (
+  Ipv4Header const &ipHeader,
+  Packet packet,
+  Ipv4RoutingProtocol::RouteReplyCallback routeReply)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << &ipHeader << ", " << &packet << &routeReply << ")");
+
+  Lookup (Ipv4RoutingProtocol::IF_INDEX_ANY, ipHeader, packet, routeReply);
 }
 
-Ipv4Route *
-Ipv4L3Protocol::Lookup (Ipv4Address dest)
+void
+Ipv4L3Protocol::Lookup (
+  uint32_t ifIndex,
+  Ipv4Header const &ipHeader,
+  Packet packet,
+  Ipv4RoutingProtocol::RouteReplyCallback routeReply)
 {
-  for (HostRoutesCI i = m_hostRoutes.begin (); 
-       i != m_hostRoutes.end (); 
-       i++) 
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << ifIndex << ", " << &ipHeader << ", " << &packet << 
+    &routeReply << ")");
+
+  for (Ipv4RoutingProtocolList::const_iterator rprotoIter = 
+         m_routingProtocols.begin ();
+       rprotoIter != m_routingProtocols.end (); 
+       rprotoIter++)
+    {
+      NS_LOG_LOGIC ("Requesting route");
+      if ((*rprotoIter).second->RequestRoute (ifIndex, ipHeader, packet, 
+                                              routeReply))
+        return;
+    }
+
+  if (ipHeader.GetDestination ().IsMulticast () && 
+      ifIndex == Ipv4RoutingProtocol::IF_INDEX_ANY)
     {
-      NS_ASSERT ((*i)->IsHost ());
-      if ((*i)->GetDest ().IsEqual (dest)) 
+      NS_LOG_LOGIC ("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)
         {
-          return (*i);
+          NS_LOG_LOGIC ("Local source. Using unicast default route for "
+            "multicast packet");
+
+          routeReply (true, *route, packet, ipHeader);
+          return;
         }
     }
-  for (NetworkRoutesI j = m_networkRoutes.begin (); 
-       j != m_networkRoutes.end (); 
-       j++) 
-    {
-      NS_ASSERT ((*j)->IsNetwork ());
-      Ipv4Mask mask = (*j)->GetDestNetworkMask ();
-      Ipv4Address entry = (*j)->GetDestNetwork ();
-      if (mask.IsMatch (dest, entry)) 
-        {
-          return (*j);
-        }
-    }
-  if (m_defaultRoute != 0) 
-    {
-      NS_ASSERT (m_defaultRoute->IsDefault ());
-      return m_defaultRoute;
-    }
-  return 0;
+//
+// No route found
+//
+  routeReply (false, Ipv4Route (), packet, ipHeader);
+}
+
+void
+Ipv4L3Protocol::AddRoutingProtocol (Ptr<Ipv4RoutingProtocol> routingProtocol,
+                                    int priority)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << &routingProtocol << ", " << priority << ")");
+  m_routingProtocols.push_back
+    (std::pair<int, Ptr<Ipv4RoutingProtocol> > (-priority, routingProtocol));
+  m_routingProtocols.sort ();
 }
 
 uint32_t 
 Ipv4L3Protocol::GetNRoutes (void)
 {
-  uint32_t n = 0;
-  if (m_defaultRoute != 0)
-    {
-      n++;
-    }
-  n += m_hostRoutes.size ();
-  n += m_networkRoutes.size ();
-  return n;
+  NS_LOG_FUNCTION;
+  return m_staticRouting->GetNRoutes ();
 }
+
 Ipv4Route *
 Ipv4L3Protocol::GetRoute (uint32_t index)
 {
-  if (index == 0 && m_defaultRoute != 0)
-    {
-      return m_defaultRoute;
-    }
-  if (index > 0 && m_defaultRoute != 0)
-    {
-      index--;
-    }
-  if (index < m_hostRoutes.size ())
-    {
-      uint32_t tmp = 0;
-      for (HostRoutesCI i = m_hostRoutes.begin (); 
-           i != m_hostRoutes.end (); 
-           i++) 
-        {
-          if (tmp  == index)
-            {
-              return *i;
-            }
-          tmp++;
-        }
-    }
-  index -= m_hostRoutes.size ();
-  uint32_t tmp = 0;
-  for (NetworkRoutesI j = m_networkRoutes.begin (); 
-       j != m_networkRoutes.end (); 
-       j++) 
-    {
-      if (tmp == index)
-        {
-          return *j;
-        }
-      tmp++;
-    }
-  NS_ASSERT (false);
-  // quiet compiler.
-  return 0;
+  NS_LOG_FUNCTION;
+  return m_staticRouting->GetRoute (index);
 }
+
 void 
 Ipv4L3Protocol::RemoveRoute (uint32_t index)
 {
-  if (index == 0 && m_defaultRoute != 0)
-    {
-      delete m_defaultRoute;
-      m_defaultRoute = 0;
-    }
-  if (index > 0 && m_defaultRoute != 0)
-    {
-      index--;
-    }
-  if (index < m_hostRoutes.size ())
-    {
-      uint32_t tmp = 0;
-      for (HostRoutesI i = m_hostRoutes.begin (); 
-           i != m_hostRoutes.end (); 
-           i++) 
-        {
-          if (tmp  == index)
-            {
-              delete *i;
-              m_hostRoutes.erase (i);
-              return;
-            }
-          tmp++;
-        }
-    }
-  index -= m_hostRoutes.size ();
-  uint32_t tmp = 0;
-  for (NetworkRoutesI j = m_networkRoutes.begin (); 
-       j != m_networkRoutes.end (); 
-       j++) 
-    {
-      if (tmp == index)
-        {
-          delete *j;
-          m_networkRoutes.erase (j);
-          return;
-        }
-      tmp++;
-    }
-  NS_ASSERT (false);
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM("(" << index << ")");
+  m_staticRouting->RemoveRoute (index);
+}
+
+void 
+Ipv4L3Protocol::AddMulticastRoute (Ipv4Address origin,
+                                   Ipv4Address group,
+                                   uint32_t inputInterface,
+                                   std::vector<uint32_t> outputInterfaces)
+{
+  NS_LOG_FUNCTION; 
+  NS_LOG_PARAM ("(" << origin << ", " << group << ", " << inputInterface << 
+    ", " << &outputInterfaces << ")");
+
+  m_staticRouting->AddMulticastRoute (origin, group, inputInterface,
+    outputInterfaces);
+}
+
+void 
+Ipv4L3Protocol::SetDefaultMulticastRoute (uint32_t outputInterface)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << outputInterface << ")");
+
+  m_staticRouting->SetDefaultMulticastRoute (outputInterface);
 }
 
+uint32_t 
+Ipv4L3Protocol::GetNMulticastRoutes (void) const
+{
+  NS_LOG_FUNCTION;
+  return m_staticRouting->GetNMulticastRoutes ();
+}
+
+Ipv4MulticastRoute *
+Ipv4L3Protocol::GetMulticastRoute (uint32_t index) const
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << index << ")");
+  return m_staticRouting->GetMulticastRoute (index);
+}
+
+void 
+Ipv4L3Protocol::RemoveMulticastRoute (Ipv4Address origin,
+                                       Ipv4Address group,
+                                       uint32_t inputInterface)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << origin << ", " << group << ", " << inputInterface << 
+    ")");
+  m_staticRouting->RemoveMulticastRoute (origin, group, inputInterface);
+}
+
+void 
+Ipv4L3Protocol::RemoveMulticastRoute (uint32_t index)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << index << ")");
+  m_staticRouting->RemoveMulticastRoute (index);
+}
 
 uint32_t 
 Ipv4L3Protocol::AddInterface (Ptr<NetDevice> device)
 {
-  Ipv4Interface *interface = new ArpIpv4Interface (m_node, device);
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << &device << ")");
+  Ptr<Ipv4Interface> interface = Create<ArpIpv4Interface> (m_node, device);
   return AddIpv4Interface (interface);
 }
+
 uint32_t 
-Ipv4L3Protocol::AddIpv4Interface (Ipv4Interface *interface)
+Ipv4L3Protocol::AddIpv4Interface (Ptr<Ipv4Interface>interface)
 {
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << interface << ")");
   uint32_t index = m_nInterfaces;
   m_interfaces.push_back (interface);
   m_nInterfaces++;
   return index;
 }
-Ipv4Interface *
+
+Ptr<Ipv4Interface>
 Ipv4L3Protocol::GetInterface (uint32_t index) const
 {
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << index << ")");
   uint32_t tmp = 0;
   for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); i++)
     {
@@ -338,15 +469,63 @@
     }
   return 0;
 }
+
 uint32_t 
 Ipv4L3Protocol::GetNInterfaces (void) const
 {
+  NS_LOG_FUNCTION;
   return m_nInterfaces;
 }
 
-Ipv4Interface *
+uint32_t 
+Ipv4L3Protocol::FindInterfaceForAddr (Ipv4Address addr) const
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << 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_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << 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_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << &device << ")");
   for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); i++)
     {
       if ((*i)->GetDevice () == device)
@@ -358,18 +537,29 @@
 }  
 
 void 
-Ipv4L3Protocol::Receive(Packet& packet, Ptr<NetDevice> device)
+Ipv4L3Protocol::Receive( Ptr<NetDevice> device, const Packet& p, uint16_t protocol, const Address &from)
 {
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << &device << ", " << &p << ", " << protocol << ", " << 
+    from << ")");
+
+  NS_LOG_LOGIC ("Packet from " << from);
+
   uint32_t index = 0;
-  for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); i++)
+  Ptr<Ipv4Interface> ipv4Interface;
+  for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); 
+       i != m_interfaces.end (); 
+       i++)
     {
-      if ((*i)->GetDevice () == device)
+      ipv4Interface = *i;
+      if (ipv4Interface->GetDevice () == device)
         {
-          m_rxTrace (packet, index);
+          m_rxTrace (p, index);
           break;
         }
       index++;
     }
+  Packet packet = p;
   Ipv4Header ipHeader;
   packet.RemoveHeader (ipHeader);
 
@@ -378,20 +568,26 @@
       return;
     }
 
-  if (Forwarding (packet, ipHeader, device)) 
+  if (Forwarding (index, packet, ipHeader, device)) 
     {
       return;
     }
 
-  ForwardUp (packet, ipHeader);
+  NS_LOG_LOGIC ("Forward up");
+  ForwardUp (packet, ipHeader, ipv4Interface);
 }
 
+
 void 
 Ipv4L3Protocol::Send (Packet const &packet, 
             Ipv4Address source, 
             Ipv4Address destination,
             uint8_t protocol)
 {
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << &packet << ", " << source << ", " << ", " << 
+    destination << ", " << protocol << ")");
+
   Ipv4Header ipHeader;
 
   ipHeader.SetSource (source);
@@ -404,53 +600,88 @@
 
   m_identification ++;
 
-  // XXX Note here that in most ipv4 stacks in the world,
-  // the route calculation for an outgoing packet is not
-  // done in the ip layer. It is done within the application
-  // socket when the first packet is sent to avoid this
-  // costly lookup on a per-packet basis.
-  // That would require us to get the route from the packet,
-  // most likely with a packet tag. The higher layers do not
-  // do this yet for us.
-  Ipv4Route *route = Lookup (ipHeader.GetDestination ());
-  if (route == 0) 
+  if (destination.IsBroadcast ())
+    {
+      uint32_t ifaceIndex = 0;
+      for (Ipv4InterfaceList::iterator ifaceIter = m_interfaces.begin ();
+           ifaceIter != m_interfaces.end (); ifaceIter++, ifaceIndex++)
+        {
+          Ptr<Ipv4Interface> outInterface = *ifaceIter;
+          Packet packetCopy = packet;
+
+          NS_ASSERT (packetCopy.GetSize () <= outInterface->GetMtu ());
+          packetCopy.AddHeader (ipHeader);
+          m_txTrace (packetCopy, ifaceIndex);
+          outInterface->Send (packetCopy, destination);
+        }
+    }
+  else
     {
-      NS_DEBUG ("not for me -- forwarding but no route to host. drop.");
+      // XXX Note here that in most ipv4 stacks in the world,
+      // the route calculation for an outgoing packet is not
+      // done in the ip layer. It is done within the application
+      // socket when the first packet is sent to avoid this
+      // costly lookup on a per-packet basis.
+      // That would require us to get the route from the packet,
+      // most likely with a packet tag. The higher layers do not
+      // do this yet for us.
+      Lookup (ipHeader, packet,
+              MakeCallback (&Ipv4L3Protocol::SendRealOut, this));
+    }
+}
+
+void
+Ipv4L3Protocol::SendRealOut (bool found,
+                             Ipv4Route const &route,
+                             Packet packet,
+                             Ipv4Header const &ipHeader)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << found << ", " << &route << ", " << &packet << 
+    &ipHeader << ")");
+
+  if (!found)
+    {
+      NS_LOG_WARN ("No route to host.  Drop.");
       m_dropTrace (packet);
       return;
     }
 
-  SendRealOut (packet, ipHeader, *route);
-}
+  NS_LOG_LOGIC ("Send via interface " << route.GetInterface ());
 
-void
-Ipv4L3Protocol::SendRealOut (Packet const &p, Ipv4Header const &ip, Ipv4Route const &route)
-{
-  Packet packet = p;
-  packet.AddHeader (ip);
-  Ipv4Interface *outInterface = GetInterface (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_LOG_LOGIC ("Send to gateway " << route.GetGateway ());
       outInterface->Send (packet, route.GetGateway ());
     } 
   else 
     {
-      outInterface->Send (packet, ip.GetDestination ());
+      NS_LOG_LOGIC ("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_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << 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_LOG_LOGIC ("For me (destination match)");
           return false;
         }
     }
@@ -458,106 +689,267 @@
   for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin ();
        i != m_interfaces.end (); i++) 
     {
-      Ipv4Interface *interface = *i;
+      Ptr<Ipv4Interface> interface = *i;
       if (interface->GetDevice () == device)
 	{
 	  if (ipHeader.GetDestination ().IsEqual (interface->GetBroadcast ())) 
 	    {
-	      NS_DEBUG ("for me 2");
+              NS_LOG_LOGIC ("For me (interface broadcast address)");
 	      return false;
 	    }
 	  break;
 	}
     }
       
-  if (ipHeader.GetDestination ().IsEqual (Ipv4Address::GetBroadcast ())) 
+  if (ipHeader.GetDestination ().IsBroadcast ()) 
     {
-      NS_DEBUG ("for me 3");
+      NS_LOG_LOGIC ("For me (Ipv4Addr broadcast address)");
       return false;
     }
+
   if (ipHeader.GetDestination ().IsEqual (Ipv4Address::GetAny ())) 
     {
-      NS_DEBUG ("for me 4");
+      NS_LOG_LOGIC ("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_LOG_LOGIC ("Not for me (TTL expired).  Drop");
       m_dropTrace (packet);
       return true;
     }
   ipHeader.SetTtl (ipHeader.GetTtl () - 1);
-  Ipv4Route *route = Lookup (ipHeader.GetDestination ());
-  if (route == 0) 
+
+  NS_LOG_LOGIC ("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++) 
     {
-      NS_DEBUG ("not for me -- forwarding but no route to host. drop.");
-      m_dropTrace (packet);
-      return true;
+      if ((*i).first.IsEqual (ipHeader.GetSource ()) &&
+          (*i).second.IsEqual (ipHeader.GetDestination ()))
+        {
+          NS_LOG_LOGIC ("For me (Joined multicast group)");
+          return false;
+        }
     }
-  NS_DEBUG ("not for me -- forwarding.");
-  SendRealOut (packet, ipHeader, *route);
+  
+  NS_LOG_LOGIC("Not for me.");
   return true;
 }
 
+void
+Ipv4L3Protocol::ForwardUp (Packet p, Ipv4Header const&ip,
+                           Ptr<Ipv4Interface> incomingInterface)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << &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 (), incomingInterface);
+}
+
+void 
+Ipv4L3Protocol::JoinMulticastGroup (Ipv4Address origin, Ipv4Address group)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << origin << ", " << group << ")");
+  m_multicastGroups.push_back(
+    std::pair<Ipv4Address, Ipv4Address> (origin, group));
+}
 
 void
-Ipv4L3Protocol::ForwardUp (Packet p, Ipv4Header const&ip)
+Ipv4L3Protocol::LeaveMulticastGroup (Ipv4Address origin, Ipv4Address group)
 {
-  Ptr<Ipv4L4Demux> demux = m_node->QueryInterface<Ipv4L4Demux> (Ipv4L4Demux::iid);
-  Ptr<Ipv4L4Protocol> protocol = demux->GetProtocol (ip.GetProtocol ());
-  protocol->Receive (p, ip.GetSource (), ip.GetDestination ());
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << 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)
 {
-  Ipv4Interface *interface = GetInterface (i);
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << i << ", " << address << ")");
+  Ptr<Ipv4Interface> interface = GetInterface (i);
   interface->SetAddress (address);
 }
+
 void 
 Ipv4L3Protocol::SetNetworkMask (uint32_t i, Ipv4Mask mask)
 {
-  Ipv4Interface *interface = GetInterface (i);
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << i << ", " << mask << ")");
+  Ptr<Ipv4Interface> interface = GetInterface (i);
   interface->SetNetworkMask (mask);
 }
+
 Ipv4Mask 
 Ipv4L3Protocol::GetNetworkMask (uint32_t i) const
 {
-  Ipv4Interface *interface = GetInterface (i);
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << i << ")");
+  Ptr<Ipv4Interface> interface = GetInterface (i);
   return interface->GetNetworkMask ();
 }
+
 Ipv4Address 
 Ipv4L3Protocol::GetAddress (uint32_t i) const
 {
-  Ipv4Interface *interface = GetInterface (i);
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << i << ")");
+  Ptr<Ipv4Interface> interface = GetInterface (i);
   return interface->GetAddress ();
 }
+
+bool
+Ipv4L3Protocol::GetIfIndexForDestination (
+  Ipv4Address destination, uint32_t& ifIndex) const
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << 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_LOG_LOGIC ("Requesting Source Address");
+      uint32_t ifIndexTmp;
+
+      if ((*i).second->RequestIfIndex (destination, ifIndexTmp))
+        {
+          NS_LOG_LOGIC ("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_LOG_LOGIC ("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_LOG_LOGIC ("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_LOG_LOGIC ("Default route specifies interface " << ifIndex);
+  return true;
+}
+
 uint16_t 
 Ipv4L3Protocol::GetMtu (uint32_t i) const
 {
-  Ipv4Interface *interface = GetInterface (i);
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << i << ")");
+  Ptr<Ipv4Interface> interface = GetInterface (i);
   return interface->GetMtu ();
 }
+
 bool 
 Ipv4L3Protocol::IsUp (uint32_t i) const
 {
-  Ipv4Interface *interface = GetInterface (i);
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << i << ")");
+  Ptr<Ipv4Interface> interface = GetInterface (i);
   return interface->IsUp ();
 }
+
 void 
 Ipv4L3Protocol::SetUp (uint32_t i)
 {
-  Ipv4Interface *interface = GetInterface (i);
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << i << ")");
+  Ptr<Ipv4Interface> interface = GetInterface (i);
   interface->SetUp ();
-}
-void 
-Ipv4L3Protocol::SetDown (uint32_t i)
-{
-  Ipv4Interface *interface = GetInterface (i);
-  interface->SetDown ();
+
+  // If interface address and network mask have been set, add a route
+  // to the network of the interface (like e.g. ifconfig does on a
+  // Linux box)
+  if ((interface->GetAddress ()) != (Ipv4Address ())
+      && (interface->GetNetworkMask ()) != (Ipv4Mask ()))
+    {
+      AddNetworkRouteTo (interface->GetAddress ().CombineMask (interface->GetNetworkMask ()),
+                         interface->GetNetworkMask (), i);
+    }
 }
 
+void 
+Ipv4L3Protocol::SetDown (uint32_t ifaceIndex)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << ifaceIndex << ")");
+  Ptr<Ipv4Interface> interface = GetInterface (ifaceIndex);
+  interface->SetDown ();
+
+  // Remove all routes that are going through this interface
+  bool modified = true;
+  while (modified)
+    {
+      modified = false;
+      for (uint32_t i = 0; i < GetNRoutes (); i++)
+        {
+          Ipv4Route *route = GetRoute (i);
+          if (route->GetInterface () == ifaceIndex)
+            {
+              RemoveRoute (i);
+              modified = true;
+              break;
+            }
+        }
+    }
+}
 
 }//namespace ns3
--- a/src/internet-node/ipv4-l3-protocol.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/ipv4-l3-protocol.h	Fri Sep 28 11:59:46 2007 +0100
@@ -25,10 +25,12 @@
 #include <list>
 #include <stdint.h>
 #include "ns3/callback-trace-source.h"
-#include "ns3/array-trace-resolver.h"
+#include "ns3/trace-context-element.h"
 #include "ns3/ipv4-address.h"
 #include "ns3/ptr.h"
-#include "l3-protocol.h"
+#include "ns3/ipv4.h"
+#include "ipv4-header.h"
+#include "ipv4-static-routing.h"
 
 namespace ns3 {
 
@@ -42,33 +44,68 @@
 class TraceResolver;
 class TraceContext;
 
-
-class Ipv4L3Protocol : public L3Protocol 
+/**
+ * \brief hold in a TraceContext the type of trace source used by this Ipv4L3Protocol
+ */
+class Ipv4L3ProtocolTraceContextElement : public TraceContextElement
 {
 public:
-  static const uint16_t PROT_NUMBER;
-
-  enum TraceType {
+  enum Type {
     TX,
     RX,
     DROP,
-    INTERFACES,
   };
-  typedef ArrayTraceResolver<Ipv4Interface>::Index InterfaceIndex;
+  Ipv4L3ProtocolTraceContextElement ();
+  Ipv4L3ProtocolTraceContextElement (enum Type type);
+  /**
+   * \returns true if this is a tx event, false otherwise.
+   */
+  bool IsTx (void) const;
+  /**
+   * \returns true if this is a rx event, false otherwise.
+   */
+  bool IsRx (void) const;
+  /**
+   * \returns true if this is a drop event, false otherwise.
+   */
+  bool IsDrop (void) const;
+  void Print (std::ostream &os) const;
+  static uint16_t GetUid (void);
+  std::string GetTypeName (void) const;
+private:
+  enum Type m_type;
+};
+
+/**
+ * \brief hold in a TraceContext the index of an Ipv4Interface within the ipv4 stack of a Node
+ */
+class Ipv4L3ProtocolInterfaceIndex : public TraceContextElement
+{
+public:
+  Ipv4L3ProtocolInterfaceIndex ();
+  Ipv4L3ProtocolInterfaceIndex (uint32_t index);
+  /**
+   * \returns the index of the Ipv4Interface within a Node.
+   */
+  uint32_t Get (void) const;
+  void Print (std::ostream &os) const;
+  static uint16_t GetUid (void);
+  std::string GetTypeName (void) const;
+private:
+  uint32_t m_index;
+};
+
+
+class Ipv4L3Protocol : public Object
+{
+public:
+  static const InterfaceId iid;
+  static const uint16_t PROT_NUMBER;
 
   Ipv4L3Protocol(Ptr<Node> node);
   virtual ~Ipv4L3Protocol ();
 
   /**
-   * \param context the trace context to use to construct the
-   *        TraceResolver to return
-   * \returns a TraceResolver which can resolve all traces
-   *          performed in this object. The caller must
-   *          delete the returned object.
-   */
-  virtual TraceResolver *CreateTraceResolver (TraceContext const &context);
-
-  /**
    * \param ttl default ttl to use
    *
    * When we need to send an ipv4 packet, we use this default
@@ -83,7 +120,7 @@
    * Try to find an Ipv4Interface whose NetDevice is equal to
    * the input NetDevice.
    */
-  Ipv4Interface *FindInterfaceForDevice (Ptr<const NetDevice> device);
+  Ptr<Ipv4Interface> FindInterfaceForDevice (Ptr<const NetDevice> device);
 
   /**
    * Lower layer calls this method after calling L3Demux::Lookup
@@ -92,7 +129,7 @@
    *    - implement a per-NetDevice ARP cache
    *    - send back arp replies on the right device
    */
-  virtual void Receive(Packet& p, Ptr<NetDevice> device);
+  void Receive( Ptr<NetDevice> device, const Packet& p, uint16_t protocol, const Address &from);
 
   /**
    * \param packet packet to send
@@ -124,57 +161,96 @@
   void SetDefaultRoute (Ipv4Address nextHop, 
                         uint32_t interface);
 
-  Ipv4Route *Lookup (Ipv4Address dest);
+  void Lookup (Ipv4Header const &ipHeader,
+               Packet packet,
+               Ipv4RoutingProtocol::RouteReplyCallback routeReply);
+
   uint32_t GetNRoutes (void);
   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);
-  Ipv4Interface * GetInterface (uint32_t i) const;
+  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);
   void SetDown (uint32_t i);
 
+  void AddRoutingProtocol (Ptr<Ipv4RoutingProtocol> routingProtocol,
+                           int priority);
 
 protected:
+
   virtual void DoDispose (void);
+  virtual Ptr<TraceResolver> GetTraceResolver (void) const;
+
 private:
-  void SendRealOut (Packet const &packet, Ipv4Header const &ip, Ipv4Route const &route);
-  bool Forwarding (Packet const &packet, Ipv4Header &ipHeader, Ptr<NetDevice> device);
-  void ForwardUp (Packet p, Ipv4Header const&ip);
-  uint32_t AddIpv4Interface (Ipv4Interface *interface);
+  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 (uint32_t ifIndex, 
+                   Packet const &packet, 
+                   Ipv4Header &ipHeader, 
+                   Ptr<NetDevice> device);
+  void ForwardUp (Packet p, Ipv4Header const&ip, Ptr<Ipv4Interface> incomingInterface);
+  uint32_t AddIpv4Interface (Ptr<Ipv4Interface> interface);
   void SetupLoopback (void);
-  TraceResolver *InterfacesCreateTraceResolver (TraceContext const &context) const;
 
-  typedef std::list<Ipv4Interface*> Ipv4InterfaceList;
-  typedef std::list<Ipv4Route *> HostRoutes;
-  typedef std::list<Ipv4Route *>::const_iterator HostRoutesCI;
-  typedef std::list<Ipv4Route *>::iterator HostRoutesI;
-  typedef std::list<Ipv4Route *> NetworkRoutes;
-  typedef std::list<Ipv4Route *>::const_iterator NetworkRoutesCI;
-  typedef std::list<Ipv4Route *>::iterator NetworkRoutesI;
+  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;
   uint32_t m_nInterfaces;
   uint8_t m_defaultTtl;
   uint16_t m_identification;
-  HostRoutes m_hostRoutes;
-  NetworkRoutes m_networkRoutes;
-  Ipv4Route *m_defaultRoute;
   Ptr<Node> m_node;
   CallbackTraceSource<Packet const &, uint32_t> m_txTrace;
   CallbackTraceSource<Packet const &, uint32_t> m_rxTrace;
   CallbackTraceSource<Packet const &> m_dropTrace;
+
+  Ipv4RoutingProtocolList m_routingProtocols;
+
+  Ptr<Ipv4StaticRouting> m_staticRouting;
+  Ipv4MulticastGroupList m_multicastGroups;
 };
 
 } // Namespace ns3
 
-#endif /* IPV$_L3_PROTOCOL_H */
+#endif /* IPV4_L3_PROTOCOL_H */
--- a/src/internet-node/ipv4-l4-demux.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/ipv4-l4-demux.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -32,6 +32,35 @@
 
 const InterfaceId Ipv4L4Demux::iid = MakeInterfaceId ("Ipv4L4Demux", Object::iid);
 
+Ipv4L4ProtocolTraceContextElement::Ipv4L4ProtocolTraceContextElement ()
+  : m_protocolNumber (0)
+{}
+Ipv4L4ProtocolTraceContextElement::Ipv4L4ProtocolTraceContextElement (int protocolNumber)
+  : m_protocolNumber (protocolNumber)
+{}
+int 
+Ipv4L4ProtocolTraceContextElement::Get (void) const
+{
+  return m_protocolNumber;
+}
+void 
+Ipv4L4ProtocolTraceContextElement::Print (std::ostream &os) const
+{
+  os << "ipv4-protocol=0x" << std::hex << m_protocolNumber << std::dec;
+}
+uint16_t 
+Ipv4L4ProtocolTraceContextElement::GetUid (void)
+{
+  static uint16_t uid = AllocateUid<Ipv4L4ProtocolTraceContextElement> ("Ipv4L4ProtocolTraceContextElement");
+  return uid;
+}
+std::string 
+Ipv4L4ProtocolTraceContextElement::GetTypeName (void) const
+{
+  return "ns3::Ipv4L4ProtocolTraceContextElement";
+}
+
+
 Ipv4L4Demux::Ipv4L4Demux (Ptr<Node> node)
   : m_node (node)
 {
@@ -54,21 +83,19 @@
   Object::DoDispose ();
 }
 
-TraceResolver *
-Ipv4L4Demux::CreateTraceResolver (TraceContext const &context)
+Ptr<TraceResolver>
+Ipv4L4Demux::GetTraceResolver (void) const
 {
-  CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
+  Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
   for (L4List_t::const_iterator i = m_protocols.begin(); i != m_protocols.end(); ++i)
     {
       Ptr<Ipv4L4Protocol> protocol = *i;
-      std::string protValue;
-      std::ostringstream oss (protValue);
-      oss << (*i)->GetProtocolNumber ();
-      Ipv4L4ProtocolTraceType protocolNumber = (*i)->GetProtocolNumber ();
-      resolver->Add (protValue,
-                     MakeCallback (&Ipv4L4Protocol::CreateTraceResolver, PeekPointer (protocol)),
-                     protocolNumber);
+      std::ostringstream oss;
+      oss << (unsigned int) (*i)->GetProtocolNumber ();
+      Ipv4L4ProtocolTraceContextElement protocolNumber = (*i)->GetProtocolNumber ();
+      resolver->AddComposite (oss.str (), protocol, protocolNumber);
     }
+  resolver->SetParentResolver (Object::GetTraceResolver ());
   return resolver;
 }
 void
--- a/src/internet-node/ipv4-l4-demux.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/ipv4-l4-demux.h	Fri Sep 28 11:59:46 2007 +0100
@@ -28,6 +28,7 @@
 #include <list>
 #include "ns3/object.h"
 #include "ns3/ptr.h"
+#include "ns3/trace-context-element.h"
 
 namespace ns3 {
 
@@ -37,25 +38,35 @@
 class TraceContext;
 
 /**
+ * \brief hold in a TraceContext the protocol number of a L4 Protocol
+ */
+class Ipv4L4ProtocolTraceContextElement : public TraceContextElement
+{
+public:
+  Ipv4L4ProtocolTraceContextElement ();
+  Ipv4L4ProtocolTraceContextElement (int protocolNumber);
+  /**
+   * \returns the protocol number as registered in the Ipv4L4Demux.
+   */
+  int Get (void) const;
+  void Print (std::ostream &os) const;
+  static uint16_t GetUid (void);
+  std::string GetTypeName (void) const;
+private:
+  int m_protocolNumber;
+};
+
+/**
  * \brief L4 Ipv4 Demux
  */
 class Ipv4L4Demux : public Object
 {
 public:
   static const InterfaceId iid;
-  typedef int Ipv4L4ProtocolTraceType;
   Ipv4L4Demux (Ptr<Node> node);
   virtual ~Ipv4L4Demux();
 
   /**
-   * \param context the trace context to use to construct the
-   *        TraceResolver to return
-   * \returns a TraceResolver which can resolve all traces
-   *          performed in this object. The caller must
-   *          delete the returned object.
-   */
-  TraceResolver *CreateTraceResolver (TraceContext const &context);
-  /**
    * \param protocol a template for the protocol to add to this L4 Demux.
    * \returns the L4Protocol effectively added.
    *
@@ -83,8 +94,10 @@
    * returned from the Ipv4L4Protocol::Insert method.
    */
   void Remove (Ptr<Ipv4L4Protocol> protocol);
+protected:
+  Ptr<TraceResolver> GetTraceResolver (void) const;
+  virtual void DoDispose (void);
 private:
-  virtual void DoDispose (void);
   typedef std::list<Ptr<Ipv4L4Protocol> > L4List_t;
   L4List_t m_protocols;
   Ptr<Node> m_node;
--- a/src/internet-node/ipv4-l4-protocol.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/ipv4-l4-protocol.h	Fri Sep 28 11:59:46 2007 +0100
@@ -26,6 +26,7 @@
 #define IPV4_L4_PROTOCOL_H
 
 #include "ns3/object.h"
+#include "ipv4-interface.h"
 
 namespace ns3 {
 
@@ -37,10 +38,6 @@
 /**
  * \brief L4 Protocol base class 
  *
- * All subclasses must implement:
- *   - Ipv4L4Protocol::Copy
- *   - Ipv4L4Protocol::CreateTraceResolver
- *
  * If you want to implement a new L4 protocol, all you have to do is
  * implement a subclass of this base class and add it to an L4Demux.
  */  
@@ -59,19 +56,19 @@
    */
   int GetVersion() const;
 
-  virtual TraceResolver *CreateTraceResolver (TraceContext const &context) = 0;
-
   /**
    * \param p packet to forward up
    * \param source source address of packet received
    * \param destination address of packet received
+   * \param incomingInterface the Ipv4Interface on which the packet arrived
    * 
    * Called from lower-level layers to send the packet up
    * in the stack. 
    */
   virtual void Receive(Packet& p, 
                        Ipv4Address const &source,
-                       Ipv4Address const &destination) = 0;
+                       Ipv4Address const &destination,
+                       Ptr<Ipv4Interface> incomingInterface) = 0;
 protected:
   virtual void DoDispose (void);
 private:
--- a/src/internet-node/ipv4-loopback-interface.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/ipv4-loopback-interface.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -19,32 +19,41 @@
  * Authors: 
  *  Mathieu Lacage <mathieu.lacage@sophia.inria.fr>,
  */
-#include "ns3/empty-trace-resolver.h"
+
+#include "ns3/log.h"
 #include "ns3/net-device.h"
 #include "ns3/node.h"
+#include "ns3/mac48-address.h"
 #include "ipv4-loopback-interface.h"
-#include "ipv4-private.h"
+#include "ipv4-l3-protocol.h"
+
+NS_LOG_COMPONENT_DEFINE ("Ipv4LoopbackInterface");
 
 namespace ns3 {
 
 Ipv4LoopbackInterface::Ipv4LoopbackInterface (Ptr<Node> node)
   : Ipv4Interface (0),
     m_node (node)
-{}
-Ipv4LoopbackInterface::~Ipv4LoopbackInterface ()
-{}
+{
+  NS_LOG_FUNCTION;
+}
 
-TraceResolver *
-Ipv4LoopbackInterface::DoCreateTraceResolver (TraceContext const &context)
+Ipv4LoopbackInterface::~Ipv4LoopbackInterface ()
 {
-  return new EmptyTraceResolver (context);
+  NS_LOG_FUNCTION;
 }
 
 void 
 Ipv4LoopbackInterface::SendTo (Packet packet, Ipv4Address dest)
 {
-  Ptr<Ipv4Private> ipv4 = m_node->QueryInterface<Ipv4Private> (Ipv4Private::iid);
-  ipv4->Receive (packet, GetDevice ());
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << &packet << ", " << dest << ")");
+
+  Ptr<Ipv4L3Protocol> ipv4 = 
+    m_node->QueryInterface<Ipv4L3Protocol> (Ipv4L3Protocol::iid);
+
+  ipv4->Receive (0, packet, Ipv4L3Protocol::PROT_NUMBER, 
+                 Mac48Address ("ff:ff:ff:ff:ff:ff"));
 }
 
 }//namespace ns3
--- a/src/internet-node/ipv4-loopback-interface.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/ipv4-loopback-interface.h	Fri Sep 28 11:59:46 2007 +0100
@@ -43,7 +43,6 @@
 
  private:
   virtual void SendTo (Packet p, Ipv4Address dest);
-  virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context);
 
   Ptr<Node> m_node;
 };
--- a/src/internet-node/ipv4-private.cc	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/* -*- 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
- * 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 "ipv4-private.h"
-#include "ipv4-l3-protocol.h"
-#include "ns3/assert.h"
-#include "ns3/net-device.h"
-
-namespace ns3 {
-
-const InterfaceId Ipv4Private::iid = MakeInterfaceId ("Ipv4Private", Object::iid);
-
-Ipv4Private::Ipv4Private (Ptr<Ipv4L3Protocol> ipv4)
-  : m_ipv4 (ipv4)
-{
-  SetInterfaceId (Ipv4Private::iid);
-}
-Ipv4Private::~Ipv4Private ()
-{
-  NS_ASSERT (m_ipv4 == 0);
-}
-TraceResolver *
-Ipv4Private::CreateTraceResolver (TraceContext const &context)
-{
-  return m_ipv4->CreateTraceResolver (context);
-}
-void 
-Ipv4Private::Send (Packet const &packet, Ipv4Address source, 
-		    Ipv4Address destination, uint8_t protocol)
-{
-  m_ipv4->Send (packet, source, destination, protocol);
-}
-Ipv4Interface *
-Ipv4Private::FindInterfaceForDevice (Ptr<const NetDevice>device)
-{
-  return m_ipv4->FindInterfaceForDevice (device);
-}
-void 
-Ipv4Private::Receive(Packet& p, Ptr<NetDevice> device)
-{
-  m_ipv4->Receive (p, device);
-}
-void 
-Ipv4Private::DoDispose (void)
-{
-  m_ipv4 = 0;
-  Object::DoDispose ();
-}
-
-} // namespace ns3
--- a/src/internet-node/ipv4-private.h	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-/* -*- 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
- * 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 IPV4_PRIVATE_H
-#define IPV4_PRIVATE_H
-
-#include "ns3/object.h"
-#include "ns3/ipv4-address.h"
-#include "ns3/ptr.h"
-#include <stdint.h>
-
-namespace ns3 {
-
-class Packet;
-class Ipv4L3Protocol;
-class TraceContext;
-class TraceResolver;
-class Ipv4Interface;
-class NetDevice;
-
-class Ipv4Private : public Object
-{
-public:
-  static const InterfaceId iid;
-  Ipv4Private (Ptr<Ipv4L3Protocol> ipv4);
-  virtual ~Ipv4Private ();
-
-  TraceResolver *CreateTraceResolver (TraceContext const &context);
-  void Send (Packet const &packet, Ipv4Address source, 
-	     Ipv4Address destination, uint8_t protocol);
-  Ipv4Interface *FindInterfaceForDevice (Ptr<const NetDevice>device);
-  void Receive(Packet& p, Ptr<NetDevice> device);
-protected:
-  virtual void DoDispose (void);
-private:
-  Ptr<Ipv4L3Protocol> m_ipv4;
-};
-
-} // namespace ns3
-
-#endif /* IPV4_PRIVATE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/internet-node/ipv4-static-routing.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,658 @@
+// -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*-
+//
+// Copyright (c) 2006 Georgia Tech Research Corporation
+// 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
+// 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: George F. Riley<riley@ece.gatech.edu>
+//         Gustavo Carneiro <gjc@inescporto.pt>
+
+#include "ns3/log.h"
+#include "ipv4-static-routing.h"
+#include "ns3/packet.h"
+
+NS_LOG_COMPONENT_DEFINE ("Ipv4StaticRouting");
+
+namespace ns3 {
+
+Ipv4StaticRouting::Ipv4StaticRouting () 
+: m_defaultRoute (0), m_defaultMulticastRoute (0)
+{
+  NS_LOG_FUNCTION;
+}
+
+void 
+Ipv4StaticRouting::AddHostRouteTo (Ipv4Address dest, 
+                                   Ipv4Address nextHop, 
+                                   uint32_t interface)
+{
+  NS_LOG_FUNCTION;
+  Ipv4Route *route = new Ipv4Route ();
+  *route = Ipv4Route::CreateHostRouteTo (dest, nextHop, interface);
+  m_hostRoutes.push_back (route);
+}
+
+void 
+Ipv4StaticRouting::AddHostRouteTo (Ipv4Address dest, 
+                                   uint32_t interface)
+{
+  NS_LOG_FUNCTION;
+  Ipv4Route *route = new Ipv4Route ();
+  *route = Ipv4Route::CreateHostRouteTo (dest, interface);
+  m_hostRoutes.push_back (route);
+}
+
+void 
+Ipv4StaticRouting::AddNetworkRouteTo (Ipv4Address network, 
+                                      Ipv4Mask networkMask, 
+                                      Ipv4Address nextHop, 
+                                      uint32_t interface)
+{
+  NS_LOG_FUNCTION;
+  Ipv4Route *route = new Ipv4Route ();
+  *route = Ipv4Route::CreateNetworkRouteTo (network,
+                                            networkMask,
+                                            nextHop,
+                                            interface);
+  m_networkRoutes.push_back (route);
+}
+
+void 
+Ipv4StaticRouting::AddNetworkRouteTo (Ipv4Address network, 
+                                      Ipv4Mask networkMask, 
+                                      uint32_t interface)
+{
+  NS_LOG_FUNCTION;
+  Ipv4Route *route = new Ipv4Route ();
+  *route = Ipv4Route::CreateNetworkRouteTo (network,
+                                            networkMask,
+                                            interface);
+  m_networkRoutes.push_back (route);
+}
+
+void 
+Ipv4StaticRouting::SetDefaultRoute (Ipv4Address nextHop, 
+                                    uint32_t interface)
+{
+  NS_LOG_FUNCTION;
+  Ipv4Route *route = new Ipv4Route ();
+  *route = Ipv4Route::CreateDefaultRoute (nextHop, interface);
+  delete m_defaultRoute;
+  m_defaultRoute = route;
+}
+
+void 
+Ipv4StaticRouting::AddMulticastRoute(Ipv4Address origin,
+                                     Ipv4Address group,
+                                     uint32_t inputInterface,
+                                     std::vector<uint32_t> outputInterfaces)
+{
+  NS_LOG_FUNCTION;
+  Ipv4MulticastRoute *route = new Ipv4MulticastRoute ();
+  *route = Ipv4MulticastRoute::CreateMulticastRoute (origin, group, 
+    inputInterface, outputInterfaces);
+  m_multicastRoutes.push_back (route);
+}
+
+void 
+Ipv4StaticRouting::SetDefaultMulticastRoute(uint32_t outputInterface)
+{
+  NS_LOG_FUNCTION;
+  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
+{
+  NS_LOG_FUNCTION;
+  return m_multicastRoutes.size () + m_defaultMulticastRoute ? 1 : 0;
+}
+
+Ipv4MulticastRoute *
+Ipv4StaticRouting::GetMulticastRoute (uint32_t index) const
+{
+  NS_LOG_FUNCTION;
+  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
+{
+  NS_LOG_FUNCTION;
+  if (m_defaultMulticastRoute != 0)
+    {
+      return m_defaultMulticastRoute;
+    }
+  return 0;
+}
+
+bool
+Ipv4StaticRouting::RemoveMulticastRoute(Ipv4Address origin,
+                                        Ipv4Address group,
+                                        uint32_t inputInterface)
+{
+  NS_LOG_FUNCTION;
+  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)
+{
+  NS_LOG_FUNCTION;
+//
+// 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)
+{
+  NS_LOG_FUNCTION;
+  for (HostRoutesCI i = m_hostRoutes.begin (); 
+       i != m_hostRoutes.end (); 
+       i++) 
+    {
+      NS_ASSERT ((*i)->IsHost ());
+      if ((*i)->GetDest ().IsEqual (dest)) 
+        {
+          return (*i);
+        }
+    }
+  for (NetworkRoutesI j = m_networkRoutes.begin (); 
+       j != m_networkRoutes.end (); 
+       j++) 
+    {
+      NS_ASSERT ((*j)->IsNetwork ());
+      Ipv4Mask mask = (*j)->GetDestNetworkMask ();
+      Ipv4Address entry = (*j)->GetDestNetwork ();
+      if (mask.IsMatch (dest, entry)) 
+        {
+          return (*j);
+        }
+    }
+  if (m_defaultRoute != 0) 
+    {
+      NS_ASSERT (m_defaultRoute->IsDefault ());
+      return m_defaultRoute;
+    }
+  return 0;
+}
+
+Ipv4MulticastRoute *
+Ipv4StaticRouting::LookupStatic (
+  Ipv4Address origin, 
+  Ipv4Address group,
+  uint32_t    ifIndex)
+{
+  NS_LOG_FUNCTION;
+//
+// 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)
+{
+  NS_LOG_FUNCTION;
+  uint32_t n = 0;
+  if (m_defaultRoute != 0)
+    {
+      n++;
+    }
+  n += m_hostRoutes.size ();
+  n += m_networkRoutes.size ();
+  return n;
+}
+
+Ipv4Route *
+Ipv4StaticRouting::GetDefaultRoute ()
+{
+  NS_LOG_FUNCTION;
+  if (m_defaultRoute != 0)
+    {
+      return m_defaultRoute;
+    }
+  else
+    {
+      return 0;
+    }
+}
+
+Ipv4Route *
+Ipv4StaticRouting::GetRoute (uint32_t index)
+{
+  NS_LOG_FUNCTION;
+  if (index == 0 && m_defaultRoute != 0)
+    {
+      return m_defaultRoute;
+    }
+  if (index > 0 && m_defaultRoute != 0)
+    {
+      index--;
+    }
+  if (index < m_hostRoutes.size ())
+    {
+      uint32_t tmp = 0;
+      for (HostRoutesCI i = m_hostRoutes.begin (); 
+           i != m_hostRoutes.end (); 
+           i++) 
+        {
+          if (tmp  == index)
+            {
+              return *i;
+            }
+          tmp++;
+        }
+    }
+  index -= m_hostRoutes.size ();
+  uint32_t tmp = 0;
+  for (NetworkRoutesI j = m_networkRoutes.begin (); 
+       j != m_networkRoutes.end (); 
+       j++) 
+    {
+      if (tmp == index)
+        {
+          return *j;
+        }
+      tmp++;
+    }
+  NS_ASSERT (false);
+  // quiet compiler.
+  return 0;
+}
+void 
+Ipv4StaticRouting::RemoveRoute (uint32_t index)
+{
+  NS_LOG_FUNCTION;
+  if (index == 0 && m_defaultRoute != 0)
+    {
+      delete m_defaultRoute;
+      m_defaultRoute = 0;
+    }
+  if (index > 0 && m_defaultRoute != 0)
+    {
+      index--;
+    }
+  if (index < m_hostRoutes.size ())
+    {
+      uint32_t tmp = 0;
+      for (HostRoutesI i = m_hostRoutes.begin (); 
+           i != m_hostRoutes.end (); 
+           i++) 
+        {
+          if (tmp  == index)
+            {
+              delete *i;
+              m_hostRoutes.erase (i);
+              return;
+            }
+          tmp++;
+        }
+    }
+  index -= m_hostRoutes.size ();
+  uint32_t tmp = 0;
+  for (NetworkRoutesI j = m_networkRoutes.begin (); 
+       j != m_networkRoutes.end (); 
+       j++) 
+    {
+      if (tmp == index)
+        {
+          delete *j;
+          m_networkRoutes.erase (j);
+          return;
+        }
+      tmp++;
+    }
+  NS_ASSERT (false);
+}
+
+bool
+Ipv4StaticRouting::RequestRoute (
+  uint32_t ifIndex,
+  Ipv4Header const &ipHeader,
+  Packet packet,
+  RouteReplyCallback routeReply)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << ifIndex << &ipHeader << ", " << &packet << ", " << 
+    &routeReply << ")");
+
+  NS_LOG_LOGIC ("source = " << ipHeader.GetSource ());
+
+  NS_LOG_LOGIC ("destination = " << ipHeader.GetDestination ());
+
+  if (ipHeader.GetDestination ().IsMulticast ())
+    {
+      NS_LOG_LOGIC ("Multicast destination");
+
+      Ipv4MulticastRoute *mRoute = LookupStatic(ipHeader.GetSource (),
+        ipHeader.GetDestination (), ifIndex);
+
+      if (mRoute)
+        {
+          NS_LOG_LOGIC ("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_LOG_LOGIC ( "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_LOG_LOGIC ("Unicast destination");
+  Ipv4Route *route = LookupStatic (ipHeader.GetDestination ());
+  if (route != 0)
+    {
+      routeReply (true, *route, packet, ipHeader);
+      return true;
+    }
+  else
+    {
+      return false; // Let other routing protocols try to handle this
+                    // route request.
+    }
+}
+
+bool
+Ipv4StaticRouting::RequestIfIndex (Ipv4Address destination, uint32_t& ifIndex)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << 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_LOG_LOGIC ("Multicast destination");
+
+      Ipv4MulticastRoute *mRoute = LookupStatic(Ipv4Address::GetAny (),
+        destination, Ipv4RoutingProtocol::IF_INDEX_ANY);
+
+      if (mRoute)
+        {
+          NS_LOG_LOGIC ("Multicast route found");
+
+          if (mRoute->GetNOutputInterfaces () != 1)
+            {
+              NS_LOG_LOGIC ("Route is to multiple interfaces.  Ignoring.");
+              return false;
+            }
+
+          ifIndex = mRoute->GetOutputInterface(0);
+          NS_LOG_LOGIC ("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_LOG_LOGIC ("Unicast destination");
+  Ipv4Route *route = LookupStatic (destination);
+  if (route)
+    {
+      ifIndex = route->GetInterface ();
+      return true;
+    }
+  else
+    {
+      return false;
+    }
+}
+
+void
+Ipv4StaticRouting::DoDispose (void)
+{
+  NS_LOG_FUNCTION;
+  for (HostRoutesI i = m_hostRoutes.begin (); 
+       i != m_hostRoutes.end (); 
+       i = m_hostRoutes.erase (i)) 
+    {
+      delete (*i);
+    }
+  for (NetworkRoutesI j = m_networkRoutes.begin (); 
+       j != m_networkRoutes.end (); 
+       j = m_networkRoutes.erase (j)) 
+    {
+      delete (*j);
+    }
+  if (m_defaultRoute != 0)
+    {
+      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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/internet-node/ipv4-static-routing.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,511 @@
+// -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*-
+//
+// Copyright (c) 2006 Georgia Tech Research Corporation
+// 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
+// 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: George F. Riley<riley@ece.gatech.edu>
+//         Gustavo Carneiro <gjc@inescporto.pt>
+//
+
+#ifndef IPV4_STATIC_ROUTING_H
+#define IPV4_STATIC_ROUTING_H
+
+#include <list>
+#include <stdint.h>
+#include "ns3/callback-trace-source.h"
+#include "ns3/array-trace-resolver.h"
+#include "ns3/ipv4-address.h"
+#include "ipv4-header.h"
+#include "ns3/ptr.h"
+#include "ns3/ipv4.h"
+
+namespace ns3 {
+
+class Packet;
+class NetDevice;
+class Ipv4Interface;
+class Ipv4Address;
+class Ipv4Header;
+class Ipv4Route;
+class Node;
+class TraceResolver;
+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 ();
+
+/**
+ * @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);
+
+private:
+  typedef std::list<Ipv4Route *> HostRoutes;
+  typedef std::list<Ipv4Route *>::const_iterator HostRoutesCI;
+  typedef std::list<Ipv4Route *>::iterator HostRoutesI;
+  typedef std::list<Ipv4Route *> NetworkRoutes;
+  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/l3-demux.cc	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,90 +0,0 @@
-// -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*-
-//
-// Copyright (c) 2006 Georgia Tech Research Corporation
-// 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
-// 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: George F. Riley<riley@ece.gatech.edu>
-//
-// Implement the L3Protocols capability for ns3.
-// George F. Riley, Georgia Tech, Fall 2006
-#include <sstream>
-#include <string>
-#include "ns3/composite-trace-resolver.h"
-#include "ns3/node.h"
-#include "l3-demux.h"
-#include "l3-protocol.h"
-
-namespace ns3 {
-
-const InterfaceId L3Demux::iid = MakeInterfaceId ("L3Demux", Object::iid);
-
-L3Demux::L3Demux (Ptr<Node> node)
-  : m_node (node)
-{
-  SetInterfaceId (L3Demux::iid);
-}
-
-L3Demux::~L3Demux()
-{}
-
-void
-L3Demux::DoDispose (void)
-{
-  for (L3Map_t::iterator i = m_protocols.begin(); i != m_protocols.end(); ++i)
-    {
-      i->second->Dispose ();
-      i->second = 0;
-    }
-  m_protocols.clear ();
-  m_node = 0;
-  Object::DoDispose ();
-}
-
-TraceResolver *
-L3Demux::CreateTraceResolver (TraceContext const &context) const
-{
-  CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
-  for (L3Map_t::const_iterator i = m_protocols.begin(); i != m_protocols.end(); ++i)
-    {
-      std::string protValue;
-      std::ostringstream oss (protValue);
-      oss << i->second->GetProtocolNumber ();
-      ProtocolTraceType context = i->second->GetProtocolNumber ();
-      resolver->Add (protValue, 
-                     MakeCallback (&L3Protocol::CreateTraceResolver, PeekPointer (i->second)),
-                     context);
-    }
-  return resolver;
-}
-  
-void L3Demux::Insert(Ptr<L3Protocol> p)
-{
-  m_protocols.insert(L3Map_t::value_type(p->GetProtocolNumber (), p));
-}
-
-Ptr<L3Protocol>
-L3Demux::GetProtocol (int p)
-{ // Look up a protocol by protocol number
-  L3Map_t::iterator i = m_protocols.find(p);
-  if (i == m_protocols.end()) 
-    {
-      return 0;
-    }
-  return i->second; // Return the protocol
-}
-
-} //namespace ns3  
-  
--- a/src/internet-node/l3-demux.h	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-// -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*-
-//
-// Copyright (c) 2006 Georgia Tech Research Corporation
-// 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
-// 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: George F. Riley<riley@ece.gatech.edu>
-//
-// Define the L3Protocols capability for ns3.
-// George F. Riley, Georgia Tech, Fall 2006
-
-// This object manages the different layer 3 protocols for any ns3
-// node that has this capability.  
-
-#ifndef L3_DEMUX_H
-#define L3_DEMUX_H
-
-#include <map>
-#include "ns3/object.h"
-#include "ns3/ptr.h"
-
-namespace ns3 {
-
-class L3Protocol;
-class Node;
-class TraceResolver;
-class TraceContext;
-
-/**
- * \brief L3 Demux 
- */
-class L3Demux : public Object
-{
-public:
-  static const InterfaceId iid;
-  typedef int ProtocolTraceType;
-  L3Demux(Ptr<Node> node);
-  virtual ~L3Demux();
-
-  /**
-   * \param context the trace context to use to construct the
-   *        TraceResolver to return
-   * \returns a TraceResolver which can resolve all traces
-   *          performed in this object. The caller must
-   *          delete the returned object.
-   */
-  TraceResolver *CreateTraceResolver (TraceContext const &context) const;
-
-
-  /**
-   * \param protocol a template for the protocol to add to this L3 Demux.
-   *
-   * Invoke Copy on the input template to get a copy of the input
-   * protocol which can be used on the Node on which this L3 Demux 
-   * is running. The new L3Protocol is registered internally as
-   * a working L3 Protocol and returned from this method.
-   * The caller does not get ownership of the returned pointer.
-   */
-  void Insert(Ptr<L3Protocol> protocol);
-  /**
-   * \param protocolNumber number of protocol to lookup
-   *        in this L4 Demux
-   * \returns a matching L3 Protocol
-   *
-   * This method is typically called by lower layers
-   * to forward packets up the stack to the right protocol.
-   * It is also called from NodeImpl::GetIpv4 for example.
-   */
-  Ptr<L3Protocol> GetProtocol (int protocolNumber);
-protected:
-  virtual void DoDispose (void);
-private:
-  typedef std::map<int, Ptr<ns3::L3Protocol> > L3Map_t;
-
-  Ptr<Node> m_node;
-  L3Map_t m_protocols;
-};
-
-} //namespace ns3
-#endif
-
--- a/src/internet-node/l3-protocol.cc	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-// -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*-
-//
-// Copyright (c) 2006 Georgia Tech Research Corporation
-// 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
-// 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: George F. Riley<riley@ece.gatech.edu>
-//
-
-// NS3 - Layer 3 Protocol base class
-// George F. Riley, Georgia Tech, Spring 2007
-
-#include "l3-protocol.h"
-
-
-namespace ns3 {
-
-L3Protocol::L3Protocol(int protocolNumber, int version)
-    : m_protocolNumber (protocolNumber),
-      m_version (version)
-{}
-L3Protocol::~L3Protocol ()
-{}
-
-int 
-L3Protocol::GetProtocolNumber (void) const
-{
-  return m_protocolNumber;
-}
-int 
-L3Protocol::GetVersion() const
-{
-  return m_version;
-}
-
-void
-L3Protocol::DoDispose (void)
-{
-  Object::DoDispose ();
-}
-
-}//namespace ns3
--- a/src/internet-node/l3-protocol.h	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-// -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*-
-//
-// Copyright (c) 2006 Georgia Tech Research Corporation
-// 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
-// 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: George F. Riley<riley@ece.gatech.edu>
-//
-
-// NS3 - Layer 3 Protocol base class
-// George F. Riley, Georgia Tech, Spring 2007
-
-#ifndef L3_PROTOCOL_H
-#define L3_PROTOCOL_H
-
-#include "ns3/object.h"
-#include "ns3/ptr.h"
-
-namespace ns3 {
-
-class Packet;
-class NetDevice;
-class TraceResolver;
-class TraceContext;
-
-/**
- * ::Send is always defined in subclasses.
- */
-class L3Protocol : public Object {
-public:
-  L3Protocol(int protocolNumber, int version);
-  virtual ~L3Protocol ();
-  /**
-   * \return The protocol number of this Layer 3 protocol
-   */  
-  int GetProtocolNumber (void) const;
-  /**
-   * \return The version number of this protocol
-   */
-  int GetVersion() const;
-
-  virtual TraceResolver *CreateTraceResolver (TraceContext const &context) = 0;
-  /**
-   * Lower layer calls this method after calling L3Demux::Lookup
-   * The ARP subclass needs to know from which NetDevice this
-   * packet is coming to:
-   *    - implement a per-NetDevice ARP cache
-   *    - send back arp replies on the right device
-   */
-  virtual void Receive(Packet& p, Ptr<NetDevice> device) = 0;
-
-protected:
-  virtual void DoDispose (void);
-private:
-  int m_protocolNumber;
-  int m_version;
-};
-
-} // Namespace ns3
-
-#endif
--- a/src/internet-node/pcap-trace.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/pcap-trace.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -22,7 +22,7 @@
 
 #include <sstream>
 
-#include "ns3/trace-root.h"
+#include "ns3/node-list.h"
 #include "ns3/trace-context.h"
 #include "ns3/callback.h"
 #include "ns3/pcap-writer.h"
@@ -50,8 +50,8 @@
 void 
 PcapTrace::TraceAllIp (void)
 {
-  TraceRoot::Connect ("/nodes/*/ipv4/(tx|rx)",
-		      MakeCallback (&PcapTrace::LogIp, this));
+  NodeList::Connect ("/nodes/*/ipv4/(tx|rx)",
+                     MakeCallback (&PcapTrace::LogIp, this));
 }
 
 PcapWriter *
@@ -82,10 +82,9 @@
 void 
 PcapTrace::LogIp (TraceContext const &context, Packet const &p, uint32_t interfaceIndex)
 {
-  NodeList::NodeIndex nodeIndex;
-  context.Get (nodeIndex);
-  uint32_t nodeId = NodeList::GetNode (nodeIndex)->GetId ();
-  PcapWriter *writer = GetStream (nodeId, interfaceIndex);
+  NodeListIndex nodeIndex;
+  context.GetElement (nodeIndex);
+  PcapWriter *writer = GetStream (nodeIndex.Get (), interfaceIndex);
   writer->WritePacket (p);
 }
 
--- a/src/internet-node/udp-header.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/udp-header.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -24,8 +24,17 @@
 
 namespace ns3 {
 
+NS_HEADER_ENSURE_REGISTERED (UdpHeader);
+
 bool UdpHeader::m_calcChecksum = false;
 
+uint32_t
+UdpHeader::GetUid (void)
+{
+  static uint32_t uid = AllocateUid<UdpHeader> ("UdpHeader.ns3");
+  return uid;
+}
+
 /* The magic values below are used only for debugging.
  * They can be used to easily detect memory corruption
  * problems so you can see the patterns in memory.
@@ -84,22 +93,27 @@
   destination.Serialize (buf+4);
   buf[8] = 0;
   buf[9] = protocol;
-  uint16_t udpLength = m_payloadSize + GetSize ();
+  uint16_t udpLength = m_payloadSize + GetSerializedSize ();
   buf[10] = udpLength >> 8;
   buf[11] = udpLength & 0xff;
 
   m_initialChecksum = Ipv4ChecksumCalculate (0, buf, 12);
 }
 
-
+std::string 
+UdpHeader::GetName (void) const
+{
+  return "UDP";
+}
 
 void 
-UdpHeader::PrintTo (std::ostream &os) const
+UdpHeader::Print (std::ostream &os) const
 {
-  os << "(udp)"
-     << ", port source=" << m_sourcePort
-     << ", port destination=" << m_destinationPort
-     << ", length=" << m_payloadSize;
+  os << "(" 
+     << "length: " << m_payloadSize + GetSerializedSize ()
+     << ") "
+     << m_sourcePort << " > " << m_destinationPort
+    ;
 }
 
 uint32_t 
@@ -109,12 +123,12 @@
 }
 
 void
-UdpHeader::SerializeTo (Buffer::Iterator start) const
+UdpHeader::Serialize (Buffer::Iterator start) const
 {
   Buffer::Iterator i = start;
   i.WriteHtonU16 (m_sourcePort);
   i.WriteHtonU16 (m_destinationPort);
-  i.WriteHtonU16 (m_payloadSize + GetSize ());
+  i.WriteHtonU16 (m_payloadSize + GetSerializedSize ());
   i.WriteU16 (0);
 
   if (m_calcChecksum) 
@@ -123,7 +137,7 @@
       //XXXX
       uint16_t checksum = Ipv4ChecksumCalculate (m_initialChecksum, 
                                                   buffer->PeekData (), 
-                                                  GetSize () + m_payloadSize);
+                                                  GetSerializedSize () + m_payloadSize);
       checksum = Ipv4ChecksumComplete (checksum);
       i = buffer->Begin ();
       i.Next (6);
@@ -132,12 +146,12 @@
     }
 }
 uint32_t
-UdpHeader::DeserializeFrom (Buffer::Iterator start)
+UdpHeader::Deserialize (Buffer::Iterator start)
 {
   Buffer::Iterator i = start;
   m_sourcePort = i.ReadNtohU16 ();
   m_destinationPort = i.ReadNtohU16 ();
-  m_payloadSize = i.ReadNtohU16 () - GetSize ();
+  m_payloadSize = i.ReadNtohU16 () - GetSerializedSize ();
   if (m_calcChecksum) 
     {
       // XXX verify checksum.
--- a/src/internet-node/udp-header.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/udp-header.h	Fri Sep 28 11:59:46 2007 +0100
@@ -23,6 +23,7 @@
 #define UDP_HEADER_H
 
 #include <stdint.h>
+#include <string>
 #include "ns3/header.h"
 #include "ns3/ipv4-address.h"
 
@@ -30,15 +31,18 @@
 /**
  * \brief Packet header for UDP packets
  */
-class UdpHeader : public Header {
+class UdpHeader : public Header 
+{
 public:
+  static uint32_t GetUid (void);
+
   /**
    * \brief Constructor
    *
    * Creates a null header
    */
   UdpHeader ();
-  virtual ~UdpHeader ();
+  ~UdpHeader ();
 
   /**
    * \brief Enable checksum calculation for UDP (XXX currently has no effect)
@@ -80,12 +84,13 @@
                            Ipv4Address destination,
                            uint8_t protocol);
 
+  std::string GetName (void) const;
+  void Print (std::ostream &os) const;
+  uint32_t GetSerializedSize (void) const;
+  void Serialize (Buffer::Iterator start) const;
+  uint32_t Deserialize (Buffer::Iterator start);
+
 private:
-  virtual void PrintTo (std::ostream &os) const;
-  virtual uint32_t GetSerializedSize (void) const;
-  virtual void SerializeTo (Buffer::Iterator start) const;
-  virtual uint32_t DeserializeFrom (Buffer::Iterator start);
-
   uint16_t m_sourcePort;
   uint16_t m_destinationPort;
   uint16_t m_payloadSize;
@@ -94,6 +99,6 @@
   static bool m_calcChecksum;
 };
 
-}; // namespace ns3
+} // namespace ns3
 
 #endif /* UDP_HEADER */
--- a/src/internet-node/udp-l4-protocol.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/udp-l4-protocol.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -19,9 +19,9 @@
  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
  */
 
+#include "ns3/log.h"
 #include "ns3/assert.h"
 #include "ns3/packet.h"
-#include "ns3/empty-trace-resolver.h"
 #include "ns3/node.h"
 
 #include "udp-l4-protocol.h"
@@ -29,10 +29,10 @@
 #include "ipv4-end-point-demux.h"
 #include "ipv4-end-point.h"
 #include "ipv4-l3-protocol.h"
-#include "ipv4-private.h"
-#include "l3-demux.h"
 #include "udp-socket.h"
 
+NS_LOG_COMPONENT_DEFINE ("UdpL4Protocol");
+
 namespace ns3 {
 
 /* see http://www.iana.org/assignments/protocol-numbers */
@@ -42,20 +42,19 @@
   : Ipv4L4Protocol (PROT_NUMBER, 2),
     m_node (node),
     m_endPoints (new Ipv4EndPointDemux ())
-{}
+{
+  NS_LOG_FUNCTION;
+}
 
 UdpL4Protocol::~UdpL4Protocol ()
-{}
-
-TraceResolver *
-UdpL4Protocol::CreateTraceResolver (TraceContext const &context)
 {
-  return new EmptyTraceResolver (context);
+  NS_LOG_FUNCTION;
 }
 
 void
 UdpL4Protocol::DoDispose (void)
 {
+  NS_LOG_FUNCTION;
   if (m_endPoints != 0)
     {
       delete m_endPoints;
@@ -68,6 +67,7 @@
 Ptr<Socket>
 UdpL4Protocol::CreateSocket (void)
 {
+  NS_LOG_FUNCTION;
   Ptr<Socket> socket = Create<UdpSocket> (m_node, this);
   return socket;
 }
@@ -75,27 +75,40 @@
 Ipv4EndPoint *
 UdpL4Protocol::Allocate (void)
 {
+  NS_LOG_FUNCTION;
   return m_endPoints->Allocate ();
 }
+
 Ipv4EndPoint *
 UdpL4Protocol::Allocate (Ipv4Address address)
 {
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << address << ")");
   return m_endPoints->Allocate (address);
 }
+
 Ipv4EndPoint *
 UdpL4Protocol::Allocate (uint16_t port)
 {
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << port << ")");
   return m_endPoints->Allocate (port);
 }
+
 Ipv4EndPoint *
 UdpL4Protocol::Allocate (Ipv4Address address, uint16_t port)
 {
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << address << ", " << port << ")");
   return m_endPoints->Allocate (address, port);
 }
 Ipv4EndPoint *
 UdpL4Protocol::Allocate (Ipv4Address localAddress, uint16_t localPort,
                Ipv4Address peerAddress, uint16_t peerPort)
 {
+  NS_LOG_FUNCTION; 
+  NS_LOG_PARAM ("(" << localAddress << ", " << localPort << ", " << 
+    peerAddress << ", " << peerPort << ")");
   return m_endPoints->Allocate (localAddress, localPort,
                                 peerAddress, peerPort);
 }
@@ -103,23 +116,31 @@
 void 
 UdpL4Protocol::DeAllocate (Ipv4EndPoint *endPoint)
 {
+  NS_LOG_FUNCTION; 
+  NS_LOG_PARAM ("(" << endPoint << ")");
   m_endPoints->DeAllocate (endPoint);
 }
 
 void 
 UdpL4Protocol::Receive(Packet& packet, 
-             Ipv4Address const &source,
-             Ipv4Address const &destination)
+                       Ipv4Address const &source,
+                       Ipv4Address const &destination,
+                       Ptr<Ipv4Interface> interface)
 {
+  NS_LOG_FUNCTION; 
+  NS_LOG_PARAM ("(" << &packet << ", " << source << ", " << destination << 
+    ")");
+
   UdpHeader udpHeader;
   packet.RemoveHeader (udpHeader);
-  Ipv4EndPoint *endPoint = m_endPoints->Lookup (destination, udpHeader.GetDestination (),
-                                                source, udpHeader.GetSource ());
-  if (endPoint == 0)
+  Ipv4EndPointDemux::EndPoints endPoints =
+    m_endPoints->Lookup (destination, udpHeader.GetDestination (),
+                         source, udpHeader.GetSource (), interface);
+  for (Ipv4EndPointDemux::EndPointsI endPoint = endPoints.begin ();
+       endPoint != endPoints.end (); endPoint++)
     {
-      return;
+      (*endPoint)->ForwardUp (packet, source, udpHeader.GetSource ());
     }
-  endPoint->ForwardUp (packet, source, udpHeader.GetSource ());
 }
 
 void
@@ -127,6 +148,10 @@
            Ipv4Address saddr, Ipv4Address daddr, 
            uint16_t sport, uint16_t dport)
 {
+  NS_LOG_FUNCTION; 
+  NS_LOG_PARAM ("(" << &packet << ", " << saddr << ", " << daddr << ", " << 
+    sport << ", " << dport << ")");
+
   UdpHeader udpHeader;
   udpHeader.SetDestination (dport);
   udpHeader.SetSource (sport);
@@ -137,9 +162,10 @@
 
   packet.AddHeader (udpHeader);
 
-  Ptr<Ipv4Private> ipv4 = m_node->QueryInterface<Ipv4Private> (Ipv4Private::iid);
+  Ptr<Ipv4L3Protocol> ipv4 = m_node->QueryInterface<Ipv4L3Protocol> (Ipv4L3Protocol::iid);
   if (ipv4 != 0)
     {
+      NS_LOG_LOGIC ("Sending to IP");
       ipv4->Send (packet, saddr, daddr, PROT_NUMBER);
     }
 }
--- a/src/internet-node/udp-l4-protocol.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/udp-l4-protocol.h	Fri Sep 28 11:59:46 2007 +0100
@@ -49,7 +49,6 @@
   UdpL4Protocol (Ptr<Node> node);
   virtual ~UdpL4Protocol ();
 
-  virtual TraceResolver *CreateTraceResolver (TraceContext const &context);
   /**
    * \return A smart Socket pointer to a UdpSocket, allocated by this instance
    * of the UDP protocol
@@ -86,7 +85,8 @@
   // inherited from Ipv4L4Protocol
   virtual void Receive(Packet& p, 
                        Ipv4Address const &source,
-                       Ipv4Address const &destination);
+                       Ipv4Address const &destination,
+                       Ptr<Ipv4Interface> interface);
 protected:
   virtual void DoDispose (void);
 private:
--- a/src/internet-node/udp-socket.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/udp-socket.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -18,11 +18,19 @@
  *
  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
  */
+
+#include "ns3/log.h"
 #include "ns3/node.h"
+#include "ns3/inet-socket-address.h"
+#include "ns3/ipv4-route.h"
+#include "ns3/ipv4.h"
 #include "udp-socket.h"
 #include "udp-l4-protocol.h"
 #include "ipv4-end-point.h"
 #include "ipv4-l4-demux.h"
+#include "ns3/ipv4.h"
+
+NS_LOG_COMPONENT_DEFINE ("UdpSocket");
 
 namespace ns3 {
 
@@ -34,9 +42,14 @@
     m_shutdownSend (false),
     m_shutdownRecv (false),
     m_connected (false)
-{}
+{
+  NS_LOG_FUNCTION;
+}
+
 UdpSocket::~UdpSocket ()
 {
+  NS_LOG_FUNCTION;
+
   m_node = 0;
   if (m_endPoint != 0)
     {
@@ -56,132 +69,189 @@
   m_udp = 0;
 }
 
+enum Socket::SocketErrno
+UdpSocket::GetErrno (void) const
+{
+  NS_LOG_FUNCTION;
+  return m_errno;
+}
+
 Ptr<Node>
 UdpSocket::GetNode (void) const
 {
+  NS_LOG_FUNCTION;
   return m_node;
 }
 
 void 
 UdpSocket::Destroy (void)
 {
+  NS_LOG_FUNCTION;
   m_node = 0;
   m_endPoint = 0;
   m_udp = 0;
 }
+
 int
 UdpSocket::FinishBind (void)
 {
-  m_endPoint->SetRxCallback (MakeCallback (&UdpSocket::ForwardUp, this));
-  m_endPoint->SetDestroyCallback (MakeCallback (&UdpSocket::Destroy, this));
+  NS_LOG_FUNCTION;
   if (m_endPoint == 0)
     {
       return -1;
     }
+  m_endPoint->SetRxCallback (MakeCallback (&UdpSocket::ForwardUp, this));
+  m_endPoint->SetDestroyCallback (MakeCallback (&UdpSocket::Destroy, this));
   return 0;
 }
 
 int
 UdpSocket::Bind (void)
 {
+  NS_LOG_FUNCTION;
   m_endPoint = m_udp->Allocate ();
   return FinishBind ();
 }
-int 
-UdpSocket::Bind (Ipv4Address address)
-{
-  m_endPoint = m_udp->Allocate (address);
-  return FinishBind ();
-}
+
 int 
-UdpSocket::Bind (uint16_t port)
+UdpSocket::Bind (const Address &address)
 {
-  m_endPoint = m_udp->Allocate (port);
-  return FinishBind ();
-}
-int 
-UdpSocket::Bind (Ipv4Address address, uint16_t port)
-{
-  m_endPoint = m_udp->Allocate (address, port);
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM("(" << address << ")");
+
+  if (!InetSocketAddress::IsMatchingType (address))
+    {
+      NS_LOG_ERROR ("Not IsMatchingType");
+      return ERROR_INVAL;
+    }
+  InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
+  Ipv4Address ipv4 = transport.GetIpv4 ();
+  uint16_t port = transport.GetPort ();
+  if (ipv4 == Ipv4Address::GetAny () && port == 0)
+    {
+      m_endPoint = m_udp->Allocate ();
+    }
+  else if (ipv4 == Ipv4Address::GetAny () && port != 0)
+    {
+      m_endPoint = m_udp->Allocate (port);
+    }
+  else if (ipv4 != Ipv4Address::GetAny () && port == 0)
+    {
+      m_endPoint = m_udp->Allocate (ipv4);
+    }
+  else if (ipv4 != Ipv4Address::GetAny () && port != 0)
+    {
+      m_endPoint = m_udp->Allocate (ipv4, port);
+    }
+
   return FinishBind ();
 }
 
-enum Socket::SocketErrno
-UdpSocket::GetErrno (void) const
-{
-  return m_errno;
-}
 int 
 UdpSocket::ShutdownSend (void)
 {
+  NS_LOG_FUNCTION;
   m_shutdownSend = true;
   return 0;
 }
+
 int 
 UdpSocket::ShutdownRecv (void)
 {
+  NS_LOG_FUNCTION;
   m_shutdownRecv = false;
   return 0;
 }
 
-void 
-UdpSocket::DoClose(ns3::Callback<void, Ptr<Socket> > closeCompleted)
+int
+UdpSocket::Close(void)
 {
-  // XXX: we should set the close state and check it in all API methods.
-  if (!closeCompleted.IsNull ())
-    {
-      closeCompleted (this);
-    }
+  NS_LOG_FUNCTION;
+  NotifyCloseCompleted ();
+  return 0;
 }
-void 
-UdpSocket::DoConnect(const Ipv4Address & address,
-                     uint16_t portNumber,
-                     ns3::Callback<void, Ptr<Socket> > connectionSucceeded,
-                     ns3::Callback<void, Ptr<Socket> > connectionFailed,
-                     ns3::Callback<void, Ptr<Socket> > halfClose)
+
+int
+UdpSocket::Connect(const Address & address)
 {
-  m_defaultAddress = address;
-  m_defaultPort = portNumber;
-  if (!connectionSucceeded.IsNull ())
-    {
-      connectionSucceeded (this);
-    }
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << address << ")");
+  Ipv4Route routeToDest;
+  InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
+  m_defaultAddress = transport.GetIpv4 ();
+  m_defaultPort = transport.GetPort ();
+  NotifyConnectionSucceeded ();
   m_connected = true;
+
+  return 0;
 }
-int
-UdpSocket::DoAccept(ns3::Callback<bool, Ptr<Socket>, const Ipv4Address&, uint16_t> connectionRequest,
-                    ns3::Callback<void, Ptr<Socket>, const Ipv4Address&, uint16_t> newConnectionCreated,
-                    ns3::Callback<void, Ptr<Socket> > closeRequested)
+
+int 
+UdpSocket::Send (const Packet &p)
 {
-  // calling accept on a udp socket is a programming error.
-  m_errno = ERROR_OPNOTSUPP;
-  return -1;
-}
-int 
-UdpSocket::DoSend (const uint8_t* buffer,
-                   uint32_t size,
-                   ns3::Callback<void, Ptr<Socket>, uint32_t> dataSent)
-{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << &p << ")");
+
   if (!m_connected)
     {
       m_errno = ERROR_NOTCONN;
       return -1;
     }
-  Packet p;
-  if (buffer == 0)
+  return DoSend (p);
+}
+
+int 
+UdpSocket::DoSend (const Packet &p)
+{
+  NS_LOG_FUNCTION;
+  if (m_endPoint == 0)
+    {
+      if (Bind () == -1)
+       {
+          NS_ASSERT (m_endPoint == 0);
+         return -1;
+       }
+      NS_ASSERT (m_endPoint != 0);
+    }
+  if (m_shutdownSend)
     {
-      p = Packet (size);
+      m_errno = ERROR_SHUTDOWN;
+      return -1;
+    } 
+  
+  return DoSendTo (p, m_defaultAddress, m_defaultPort);
+}
+
+int
+UdpSocket::DoSendTo (const Packet &p, const Address &address)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << &p << ", " << address << ")");
+
+  if (!m_connected)
+    {
+      NS_LOG_LOGIC ("Not connected");
+      InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
+      Ipv4Address ipv4 = transport.GetIpv4 ();
+      uint16_t port = transport.GetPort ();
+      return DoSendTo (p, ipv4, port);
     }
   else
     {
-      p = Packet (buffer, size);
+      // connected UDP socket must use default addresses
+      NS_LOG_LOGIC ("Connected");
+      return DoSendTo (p, m_defaultAddress, m_defaultPort);
     }
-  return DoSendPacketTo (p, m_defaultAddress, m_defaultPort, dataSent);
 }
+
 int
-UdpSocket::DoSendPacketTo (const Packet &p, Ipv4Address daddr, uint16_t dport,
-                           ns3::Callback<void, Ptr<Socket>, uint32_t> dataSent)
+UdpSocket::DoSendTo (const Packet &p, Ipv4Address dest, uint16_t port)
 {
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << &p << ", " << dest << ", " << port << ")");
+
+  Ipv4Route routeToDest;
+
   if (m_endPoint == 0)
     {
       if (Bind () == -1)
@@ -196,64 +266,198 @@
       m_errno = ERROR_SHUTDOWN;
       return -1;
     }
-  m_udp->Send (p, m_endPoint->GetLocalAddress (), daddr,
-		   m_endPoint->GetLocalPort (), dport);
-  if (!dataSent.IsNull ())
+
+  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 ())
     {
-      dataSent (this, p.GetSize ());
+      NS_LOG_LOGIC ("Limited broadcast");
+      for (uint32_t i = 0; i < ipv4->GetNInterfaces (); i++ )
+        {
+          Ipv4Address addri = ipv4->GetAddress (i);
+          Ipv4Mask maski = ipv4->GetNetworkMask (i);
+          m_udp->Send (p, addri, addri.GetSubnetDirectedBroadcast (maski),
+                       m_endPoint->GetLocalPort (), port);
+          NotifyDataSent (p.GetSize ());
+        }
     }
+  else if (ipv4->GetIfIndexForDestination(dest, localIfIndex))
+    {
+      NS_LOG_LOGIC ("Route exists");
+      m_udp->Send (p, ipv4->GetAddress (localIfIndex), dest,
+		   m_endPoint->GetLocalPort (), port);
+      NotifyDataSent (p.GetSize ());
+      return 0;
+    }
+  else
+   {
+      NS_LOG_ERROR ("ERROR_NOROUTETOHOST");
+      m_errno = ERROR_NOROUTETOHOST;
+      return -1;
+   }
+
   return 0;
 }
+
 int 
-UdpSocket::DoSendTo(const Ipv4Address &address,
-                    uint16_t port,
-                    const uint8_t *buffer,
-                    uint32_t size,
-                    ns3::Callback<void, Ptr<Socket>, uint32_t> dataSent)
+UdpSocket::SendTo(const Address &address, const Packet &p)
 {
-  if (m_connected)
-    {
-      m_errno = ERROR_ISCONN;
-      return -1;
-    }
-  Packet p;
-  if (buffer == 0)
-    {
-      p = Packet (size);
-    }
-  else
-    {
-      p = Packet (buffer, size);
-    }
-  return DoSendPacketTo (p, address, port, dataSent);
-}
-void 
-UdpSocket::DoRecv(ns3::Callback<void, Ptr<Socket>, const uint8_t*, uint32_t,const Ipv4Address&, uint16_t> callback)
-{
-  m_rxCallback = callback;
-}
-void 
-UdpSocket::DoRecvDummy(ns3::Callback<void, Ptr<Socket>, uint32_t,const Ipv4Address&, uint16_t> callback)
-{
-  m_dummyRxCallback = callback;
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << address << ", " << &p << ")");
+  InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
+  Ipv4Address ipv4 = transport.GetIpv4 ();
+  uint16_t port = transport.GetPort ();
+  return DoSendTo (p, ipv4, port);
 }
 
 void 
-UdpSocket::ForwardUp (const Packet &packet, Ipv4Address saddr, uint16_t sport)
+UdpSocket::ForwardUp (const Packet &packet, Ipv4Address ipv4, uint16_t port)
 {
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << &packet << ", " << ipv4 << ", " << port << ")");
+
   if (m_shutdownRecv)
     {
       return;
     }
+  
+  Address address = InetSocketAddress (ipv4, port);
   Packet p = packet;
-  if (!m_dummyRxCallback.IsNull ())
-    {
-      m_dummyRxCallback (this, p.GetSize (), saddr, sport);
-    }
-  if (!m_rxCallback.IsNull ())
-    {
-      m_rxCallback (this, p.PeekData (), p.GetSize (), saddr, sport);
-    }
+  NotifyDataReceived (p, address);
+}
+
+} //namespace ns3
+
+
+#ifdef RUN_SELF_TESTS
+
+#include "ns3/test.h"
+#include "ns3/internet-node.h"
+#include "ns3/socket-factory.h"
+#include "ns3/udp.h"
+#include "ns3/simulator.h"
+#include "ns3/point-to-point-channel.h"
+#include "ns3/point-to-point-net-device.h"
+#include "ns3/drop-tail-queue.h"
+#include <string>
+
+namespace ns3 {
+
+class UdpSocketTest: public Test
+{
+  Packet m_receivedPacket;
+  Packet m_receivedPacket2;
+
+public:
+  virtual bool RunTests (void);
+  UdpSocketTest ();
+
+  void ReceivePacket (Ptr<Socket> socket, const Packet &packet, const Address &from);
+  void ReceivePacket2 (Ptr<Socket> socket, const Packet &packet, const Address &from);
+};
+
+
+UdpSocketTest::UdpSocketTest ()
+  : Test ("UdpSocket") {}
+
+
+void UdpSocketTest::ReceivePacket (Ptr<Socket> socket, const Packet &packet, const Address &from)
+{
+  m_receivedPacket = packet;
+}
+
+void UdpSocketTest::ReceivePacket2 (Ptr<Socket> socket, const Packet &packet, const Address &from)
+{
+  m_receivedPacket2 = packet;
 }
 
-}//namespace ns3
+bool
+UdpSocketTest::RunTests (void)
+{
+  bool result = true;
+
+  // Create topology
+  
+  // Receiver Node
+  Ptr<Node> rxNode = Create<InternetNode> ();
+  Ptr<PointToPointNetDevice> rxDev = Create<PointToPointNetDevice> (rxNode);
+  rxDev->AddQueue(Create<DropTailQueue> ());
+  Ptr<Ipv4> ipv4 = rxNode->QueryInterface<Ipv4> (Ipv4::iid);
+  uint32_t netdev_idx = ipv4->AddInterface (rxDev);
+  ipv4->SetAddress (netdev_idx, Ipv4Address ("10.0.0.1"));
+  ipv4->SetNetworkMask (netdev_idx, Ipv4Mask (0xffff0000U));
+  ipv4->SetUp (netdev_idx);
+
+  // Sender Node
+  Ptr<Node> txNode = Create<InternetNode> ();
+  Ptr<PointToPointNetDevice> txDev = Create<PointToPointNetDevice> (txNode);
+  txDev->AddQueue(Create<DropTailQueue> ());
+  ipv4 = txNode->QueryInterface<Ipv4> (Ipv4::iid);
+  netdev_idx = ipv4->AddInterface (txDev);
+  ipv4->SetAddress (netdev_idx, Ipv4Address ("10.0.0.2"));
+  ipv4->SetNetworkMask (netdev_idx, Ipv4Mask (0xffff0000U));
+  ipv4->SetUp (netdev_idx);
+
+  // link the two nodes
+  Ptr<PointToPointChannel> channel = Create<PointToPointChannel> ();
+  rxDev->Attach (channel);
+  txDev->Attach (channel);
+
+
+  // Create the UDP sockets
+  Ptr<SocketFactory> rxSocketFactory = rxNode->QueryInterface<SocketFactory> (Udp::iid);
+  Ptr<Socket> rxSocket = rxSocketFactory->CreateSocket ();
+  NS_TEST_ASSERT_EQUAL (rxSocket->Bind (InetSocketAddress (Ipv4Address ("10.0.0.2"), 1234)), 0);
+  rxSocket->SetRecvCallback (MakeCallback (&UdpSocketTest::ReceivePacket, this));
+
+  Ptr<SocketFactory> txSocketFactory = txNode->QueryInterface<SocketFactory> (Udp::iid);
+  Ptr<Socket> txSocket = txSocketFactory->CreateSocket ();
+
+  // ------ Now the tests ------------
+
+  // Unicast test
+  m_receivedPacket = Packet ();
+  NS_TEST_ASSERT_EQUAL (txSocket->SendTo (InetSocketAddress (Ipv4Address("10.0.0.1"), 1234),
+                                          Packet (123)), 0);
+  Simulator::Run ();
+  NS_TEST_ASSERT_EQUAL (m_receivedPacket.GetSize (), 123);
+
+
+  // Simple broadcast test
+
+  m_receivedPacket = Packet ();
+  NS_TEST_ASSERT_EQUAL (txSocket->SendTo (InetSocketAddress (Ipv4Address("255.255.255.255"), 1234),
+                                          Packet (123)), 0);
+  Simulator::Run ();
+  NS_TEST_ASSERT_EQUAL (m_receivedPacket.GetSize (), 123);
+
+  // Broadcast test with multiple receiving sockets
+
+  // When receiving broadcast packets, all sockets sockets bound to
+  // the address/port should receive a copy of the same packet.
+  Ptr<Socket> rxSocket2 = rxSocketFactory->CreateSocket ();
+  rxSocket2->SetRecvCallback (MakeCallback (&UdpSocketTest::ReceivePacket2, this));
+  NS_TEST_ASSERT_EQUAL (rxSocket2->Bind (InetSocketAddress (Ipv4Address ("0.0.0.0"), 1234)), 0);
+
+  m_receivedPacket = Packet ();
+  m_receivedPacket2 = Packet ();
+  NS_TEST_ASSERT_EQUAL (txSocket->SendTo (InetSocketAddress (Ipv4Address("255.255.255.255"), 1234),
+                                          Packet (123)), 0);
+  Simulator::Run ();
+  NS_TEST_ASSERT_EQUAL (m_receivedPacket.GetSize (), 123);
+  NS_TEST_ASSERT_EQUAL (m_receivedPacket2.GetSize (), 123);
+
+  return result;
+}
+
+
+static UdpSocketTest gUdpSocketTest;
+
+}; // namespace ns3
+
+#endif /* RUN_SELF_TESTS */
--- a/src/internet-node/udp-socket.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/udp-socket.h	Fri Sep 28 11:59:46 2007 +0100
@@ -25,6 +25,7 @@
 #include "ns3/callback.h"
 #include "ns3/socket.h"
 #include "ns3/ptr.h"
+#include "ns3/ipv4-address.h"
 
 namespace ns3 {
 
@@ -45,49 +46,33 @@
   virtual enum SocketErrno GetErrno (void) const;
   virtual Ptr<Node> GetNode (void) const;
   virtual int Bind (void);
-  virtual int Bind (Ipv4Address address);
-  virtual int Bind (uint16_t port); 
-  virtual int Bind (Ipv4Address address, uint16_t port);
+  virtual int Bind (const Address &address);
+  virtual int Close (void);
   virtual int ShutdownSend (void);
   virtual int ShutdownRecv (void);
+  virtual int Connect(const Address &address);
+  virtual int Send (const Packet &p);
+  virtual int SendTo(const Address &address,const Packet &p);
 
 private:
-  virtual void DoClose(ns3::Callback<void, Ptr<Socket> > closeCompleted);
-  virtual void DoConnect(const Ipv4Address & address,
-			 uint16_t portNumber,
-			 ns3::Callback<void, Ptr<Socket> > connectionSucceeded,
-			 ns3::Callback<void, Ptr<Socket> > connectionFailed,
-			 ns3::Callback<void, Ptr<Socket> > halfClose);
-  virtual int DoAccept(ns3::Callback<bool, Ptr<Socket>, const Ipv4Address&, uint16_t> connectionRequest,
-		       ns3::Callback<void, Ptr<Socket>, const Ipv4Address&, uint16_t> newConnectionCreated,
-		       ns3::Callback<void, Ptr<Socket> > closeRequested);
-  virtual int DoSend (const uint8_t* buffer,
-                    uint32_t size,
-                    ns3::Callback<void, Ptr<Socket>, uint32_t> dataSent);
-  virtual int DoSendTo(const Ipv4Address &address,
-                      uint16_t port,
-                      const uint8_t *buffer,
-                      uint32_t size,
-                      ns3::Callback<void, Ptr<Socket>, uint32_t> dataSent);
-  virtual void DoRecv(ns3::Callback<void, Ptr<Socket>, const uint8_t*, uint32_t,const Ipv4Address&, uint16_t>);
-  virtual void DoRecvDummy(ns3::Callback<void, Ptr<Socket>, uint32_t,const Ipv4Address&, uint16_t>);
 
 private:
   friend class Udp;
   // invoked by Udp class
   int FinishBind (void);
-  void ForwardUp (const Packet &p, Ipv4Address saddr, uint16_t sport);
+  void ForwardUp (const Packet &p, Ipv4Address ipv4, uint16_t port);
   void Destroy (void);
-  int DoSendPacketTo (const Packet &p, Ipv4Address daddr, uint16_t dport,
-		      ns3::Callback<void, Ptr<Socket>, uint32_t> dataSent);
+  int DoSend (const Packet &p);
+  int DoSendTo (const Packet &p, const Address &daddr);
+  int DoSendTo (const Packet &p, Ipv4Address daddr, uint16_t dport);
 
   Ipv4EndPoint *m_endPoint;
   Ptr<Node> m_node;
   Ptr<UdpL4Protocol> m_udp;
   Ipv4Address m_defaultAddress;
   uint16_t m_defaultPort;
-  Callback<void,Ptr<Socket>,uint32_t,const Ipv4Address &,uint16_t> m_dummyRxCallback;
-  Callback<void,Ptr<Socket>,uint8_t const*,uint32_t,const Ipv4Address &,uint16_t> m_rxCallback;
+  Callback<void,Ptr<Socket>,uint32_t,const Address &> m_dummyRxCallback;
+  Callback<void,Ptr<Socket>,uint8_t const*,uint32_t,const Address &> m_rxCallback;
   enum SocketErrno m_errno;
   bool m_shutdownSend;
   bool m_shutdownRecv;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/internet-node/waf	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,1 @@
+exec "`dirname "$0"`"/../../waf "$@"
\ No newline at end of file
--- a/src/internet-node/wscript	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/internet-node/wscript	Fri Sep 28 11:59:46 2007 +0100
@@ -1,19 +1,10 @@
 ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
 
 
-def configure(conf):
-    conf.env.append_value('NS3_MODULES', 'ns3-internet-node')
-
-
 def build(bld):
-    obj = bld.create_obj('cpp', 'shlib')
-    obj.name = 'ns3-internet-node'
-    obj.target = obj.name
-    obj.uselib_local = ['ns3-node', 'ns3-applications']
+    obj = bld.create_ns3_module('internet-node', ['node'])
     obj.source = [
         'internet-node.cc',
-        'l3-demux.cc',
-        'l3-protocol.cc',
         'ipv4-l4-demux.cc',
         'ipv4-l4-protocol.cc',
         'ipv4-header.cc',
@@ -21,6 +12,7 @@
         'ipv4-checksum.cc',
         'ipv4-interface.cc',
         'ipv4-l3-protocol.cc',
+        'ipv4-static-routing.cc',
         'ipv4-end-point.cc',
         'udp-l4-protocol.cc',
         'arp-header.cc',
@@ -28,12 +20,9 @@
         'arp-ipv4-interface.cc',
         'arp-l3-protocol.cc',
         'ipv4-loopback-interface.cc',
-        'header-utils.cc',
         'udp-socket.cc',
         'ipv4-end-point-demux.cc',
-        'arp-private.cc',
         'ipv4-impl.cc',
-        'ipv4-private.cc',
         'ascii-trace.cc',
         'pcap-trace.cc',
         'udp-impl.cc',
@@ -44,4 +33,6 @@
         'internet-node.h',
         'ascii-trace.h',
         'pcap-trace.h',
+        'ipv4-header.h',
+        'udp-header.h',
         ]
--- a/src/mobility/grid-topology.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/grid-topology.cc	Fri Sep 28 11:59:46 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
@@ -44,7 +43,10 @@
   double x, y;
   x = m_xMin + m_deltaX * (i % m_n);
   y = m_yMin + m_deltaY * (i / m_n);
-  object->AddInterface (ComponentManager::Create (m_positionClassId, x, y));
+  Ptr<MobilityModel> mobility = ComponentManager::Create<MobilityModel> (m_positionClassId,
+                                                                         MobilityModel::iid);
+  object->AddInterface (mobility);
+  mobility->Set (Position (x, y, 0.0));
 }
 
 void 
@@ -53,7 +55,10 @@
   double x, y;
   x = m_xMin + m_deltaX * (i / m_n);
   y = m_yMin + m_deltaY * (i % m_n);
-  object->AddInterface (ComponentManager::Create (m_positionClassId, x, y));
+  Ptr<MobilityModel> mobility = ComponentManager::Create<MobilityModel> (m_positionClassId, 
+                                                                         MobilityModel::iid);
+  object->AddInterface (mobility);
+  mobility->Set (Position (x, y, 0.0));
 }
 
 
--- a/src/mobility/grid-topology.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/grid-topology.h	Fri Sep 28 11:59:46 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	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/hierarchical-mobility-model.cc	Fri Sep 28 11:59:46 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
@@ -41,8 +40,8 @@
       parentNotifier = Create<MobilityModelNotifier> ();
       parent->AddInterface (parentNotifier);
     }
-  childNotifier->RegisterListener (MakeCallback (&HierarchicalMobilityModel::ChildChanged, this));
-  parentNotifier->RegisterListener (MakeCallback (&HierarchicalMobilityModel::ParentChanged, this));
+  childNotifier->TraceConnect ("/course-changed", MakeCallback (&HierarchicalMobilityModel::ChildChanged, this));
+  parentNotifier->TraceConnect ("/course-changed", MakeCallback (&HierarchicalMobilityModel::ParentChanged, this));
 }
 
 Ptr<MobilityModel> 
@@ -89,13 +88,13 @@
 }
 
 void 
-HierarchicalMobilityModel::ParentChanged (Ptr<const MobilityModel> model)
+HierarchicalMobilityModel::ParentChanged (const TraceContext &context, Ptr<const MobilityModel> model)
 {
   MobilityModel::NotifyCourseChange ();
 }
 
 void 
-HierarchicalMobilityModel::ChildChanged (Ptr<const MobilityModel> model)
+HierarchicalMobilityModel::ChildChanged (const TraceContext &context, Ptr<const MobilityModel> model)
 {
   MobilityModel::NotifyCourseChange ();
 }
--- a/src/mobility/hierarchical-mobility-model.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/hierarchical-mobility-model.h	Fri Sep 28 11:59:46 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
@@ -63,8 +62,8 @@
   virtual void DoSet (const Position &position);
   virtual Speed DoGetSpeed (void) const;
 
-  void ParentChanged (Ptr<const MobilityModel> model);
-  void ChildChanged (Ptr<const MobilityModel> model);
+  void ParentChanged (const TraceContext &context, Ptr<const MobilityModel> model);
+  void ChildChanged (const TraceContext &context, Ptr<const MobilityModel> model);
 
   Ptr<MobilityModel> m_child;
   Ptr<MobilityModel> m_parent;
--- a/src/mobility/mobility-model-notifier.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/mobility-model-notifier.cc	Fri Sep 28 11:59:46 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
@@ -19,6 +18,8 @@
  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
  */
 #include "mobility-model-notifier.h"
+#include "ns3/composite-trace-resolver.h"
+#include "ns3/trace-doc.h"
 
 namespace ns3 {
 
@@ -33,36 +34,23 @@
 }
 
 void 
-MobilityModelNotifier::RegisterListener (Listener listener)
-{
-  m_listeners.push_back (listener);
-}
-void 
-MobilityModelNotifier::UnregisterListener (Listener callback)
-{
-  for (std::list<Listener>::iterator i = m_listeners.begin ();
-       i != m_listeners.end ();)
-    {
-      Listener listener = *i;
-      if (listener.IsEqual (callback))
-	{
-	  i = m_listeners.erase (i);
-	}
-      else
-	{
-	  i++;
-	}
-    }  
-}
-void 
 MobilityModelNotifier::Notify (Ptr<const MobilityModel> position) const
 {
-  for (std::list<Listener>::const_iterator i = m_listeners.begin ();
-       i != m_listeners.end (); i++)
-    {
-      Listener listener = *i;
-      listener (position);
-    }
+  m_trace (position);
+}
+
+Ptr<TraceResolver> 
+MobilityModelNotifier::GetTraceResolver (void) const
+{
+  Ptr<CompositeTraceResolver> resolver = 
+    Create<CompositeTraceResolver> ();
+  resolver->AddSource ("course-change", 
+                       TraceDoc ("The value of the speed vector changed",
+                                 "Ptr<const MobilityModel>", 
+                                 "the mobility model whose course changed"),
+                       m_trace);
+  resolver->SetParentResolver (Object::GetTraceResolver ());
+  return resolver;
 }
 
 } // namespace ns3
--- a/src/mobility/mobility-model-notifier.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/mobility-model-notifier.h	Fri Sep 28 11:59:46 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
@@ -24,6 +23,7 @@
 #include "ns3/object.h"
 #include "ns3/component-manager.h"
 #include "ns3/callback.h"
+#include "ns3/callback-trace-source.h"
 #include "mobility-model.h"
 
 namespace ns3 {
@@ -37,8 +37,6 @@
   static const InterfaceId iid;
   static const ClassId cid;
 
-  typedef Callback<void,Ptr<const MobilityModel> > Listener;
-
   /**
    * Create a new position notifier
    */
@@ -48,23 +46,10 @@
    * \param position the position which just changed.
    */
   void Notify (Ptr<const MobilityModel> position) const;
-
-  /**
-   * \param listener listener to add
-   *
-   * The listener will be notified upon every position change.
-   */
-  void RegisterListener (Listener listener);
-  /**
-   * \param listener listener to remove
-   *
-   * The listener will not be notified anymore upon every 
-   * position change. It is not an error to try to unregister
-   * a non-registered liste
-   */
-  void UnregisterListener (Listener listener);
+protected:
+  virtual Ptr<TraceResolver> GetTraceResolver (void) const;
 private:
-  std::list<Listener> m_listeners;
+  CallbackTraceSource<Ptr<const MobilityModel> > m_trace;
 };
 
 } // namespace ns3
--- a/src/mobility/mobility-model.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/mobility-model.cc	Fri Sep 28 11:59:46 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
@@ -52,9 +51,9 @@
 }
 
 double 
-MobilityModel::GetDistanceFrom (const MobilityModel &other) const
+MobilityModel::GetDistanceFrom (Ptr<const MobilityModel> other) const
 {
-  Position oPosition = other.DoGet ();
+  Position oPosition = other->DoGet ();
   Position position = DoGet ();
   return CalculateDistance (position, oPosition);
 }
--- a/src/mobility/mobility-model.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/mobility-model.h	Fri Sep 28 11:59:46 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
@@ -57,7 +56,7 @@
    * \param position a reference to another mobility model
    * \returns the distance between the two objects. Unit is meters.
    */
-  double GetDistanceFrom (const MobilityModel &position) const;
+  double GetDistanceFrom (Ptr<const MobilityModel> position) const;
 protected:
   /**
    * Must be invoked by subclasses when the course of the
--- a/src/mobility/position.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/position.cc	Fri Sep 28 11:59:46 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	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/position.h	Fri Sep 28 11:59:46 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>
+ */
 #ifndef POSITION_H
 #define POSITION_H
 
--- a/src/mobility/random-position.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/random-position.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -1,11 +1,30 @@
+/* -*-  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"
 #include "ns3/random-variable-default-value.h"
-#include "ns3/debug.h"
+#include "ns3/log.h"
 #include <cmath>
 
-NS_DEBUG_COMPONENT_DEFINE ("RandomPosition");
+NS_LOG_COMPONENT_DEFINE ("RandomPosition");
 
 namespace ns3 {
 
@@ -22,19 +41,19 @@
 static RandomVariableDefaultValue
 g_discTheta ("RandomDiscPositionTheta",
 	     "A random variable which represents the angle (gradients) of a position in a random disc.",
-	     "Uniform:0:3.1415");
+	     "Uniform:0:6.2830");
 
 static RandomVariableDefaultValue
 g_discRho ("RandomDiscPositionRho",
 	   "A random variable which represents the radius of a position in a random disc.",
 	   "Uniform:0:200");
 
-static IntegerDefaultValue<double>
+static NumericDefaultValue<double>
 g_discX ("RandomDiscPositionX",
 	 "The x coordinate of the center of the random position disc.",
 	 0.0);
 
-static IntegerDefaultValue<double>
+static NumericDefaultValue<double>
 g_discY ("RandomDiscPositionY",
 	 "The y coordinate of the center of the random position disc.",
 	 0.0);
@@ -108,7 +127,7 @@
   double rho = m_rho->GetValue ();
   double x = m_x + std::cos (theta) * rho;
   double y = m_y + std::sin (theta) * rho;
-  NS_DEBUG ("Disc position x=" << x << ", y=" << y);
+  NS_LOG_DEBUG ("Disc position x=" << x << ", y=" << y);
   return Position (x, y, 0.0);
 }
 
--- a/src/mobility/random-position.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/random-position.h	Fri Sep 28 11:59:46 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>
+ */
 #ifndef RANDOM_POSITION_H
 #define RANDOM_POSITION_H
 
--- a/src/mobility/random-topology.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/random-topology.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -69,9 +69,9 @@
 {
   Ptr<MobilityModel> mobility = ComponentManager::Create<MobilityModel> (m_mobilityModel, 
                                                                          MobilityModel::iid);
+  object->AddInterface (mobility);
   Position position = m_positionModel->Get ();
   mobility->Set (position);
-  object->AddInterface (mobility);
 }
 
 
--- a/src/mobility/rectangle-default-value.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/rectangle-default-value.cc	Fri Sep 28 11:59:46 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	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/rectangle-default-value.h	Fri Sep 28 11:59:46 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	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/rectangle.cc	Fri Sep 28 11:59:46 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	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/rectangle.h	Fri Sep 28 11:59:46 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	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/speed.cc	Fri Sep 28 11:59:46 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	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/speed.h	Fri Sep 28 11:59:46 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>
+ */
 #ifndef SPEED_H
 #define SPEED_H
 
--- a/src/mobility/static-mobility-model.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/static-mobility-model.cc	Fri Sep 28 11:59:46 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	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/static-mobility-model.h	Fri Sep 28 11:59:46 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	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/static-speed-helper.cc	Fri Sep 28 11:59:46 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	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/static-speed-helper.h	Fri Sep 28 11:59:46 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>
+ */
 #ifndef STATIC_SPEED_HELPER_H
 #define STATIC_SPEED_HELPER_H
 
--- a/src/mobility/static-speed-mobility-model.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/static-speed-mobility-model.cc	Fri Sep 28 11:59:46 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	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/mobility/static-speed-mobility-model.h	Fri Sep 28 11:59:46 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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mobility/waf	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,1 @@
+exec "`dirname "$0"`"/../../waf "$@"
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mobility/wscript	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,38 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def build(bld):
+    mobility = bld.create_ns3_module('mobility', ['core', 'simulator'])
+    mobility.source = [
+        'grid-topology.cc',
+        'hierarchical-mobility-model.cc',
+        'mobility-model.cc',
+        'mobility-model-notifier.cc',
+        'position.cc',
+        'random-position.cc',
+        'random-topology.cc',
+        'rectangle.cc',
+        'rectangle-default-value.cc',
+        'speed.cc',
+        'static-mobility-model.cc',
+        'static-speed-helper.cc',
+        'static-speed-mobility-model.cc',
+        'random-waypoint-mobility-model.cc',
+        ]
+
+    headers = bld.create_obj('ns3header')
+    headers.source = [
+        'grid-topology.h',
+        'hierarchical-mobility-model.h',
+        'mobility-model.h',
+        'mobility-model-notifier.h',
+        'position.h',
+        'random-position.h',
+        'random-topology.h',
+        'rectangle.h',
+        'rectangle-default-value.h',
+        'speed.h',
+        'static-mobility-model.h',
+        'static-speed-helper.h',
+        'static-speed-mobility-model.h',
+        'random-waypoint-mobility-model.h',
+        ]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/address-utils.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,59 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 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
+ * 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 "address-utils.h"
+
+namespace ns3 {
+
+void WriteTo (Buffer::Iterator &i, Ipv4Address ad)
+{
+  i.WriteHtonU32 (ad.GetHostOrder ());
+}
+void WriteTo (Buffer::Iterator &i, const Address &ad)
+{
+  uint8_t mac[Address::MAX_SIZE];
+  ad.CopyTo (mac);
+  i.Write (mac, ad.GetLength ());
+}
+void WriteTo (Buffer::Iterator &i, Mac48Address ad)
+{
+  uint8_t mac[6];
+  ad.CopyTo (mac);
+  i.Write (mac, 6);
+}
+
+void ReadFrom (Buffer::Iterator &i, Ipv4Address &ad)
+{
+  ad.SetHostOrder (i.ReadNtohU32 ());
+}
+void ReadFrom (Buffer::Iterator &i, Address &ad, uint32_t len)
+{
+  uint8_t mac[Address::MAX_SIZE];
+  i.Read (mac, len);
+  ad.CopyFrom (mac, len);
+}
+void ReadFrom (Buffer::Iterator &i, Mac48Address &ad)
+{
+  uint8_t mac[6];
+  i.Read (mac, 6);
+  ad.CopyFrom (mac);
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/address-utils.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,41 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 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
+ * 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 ADDRESS_UTILS_H
+#define ADDRESS_UTILS_H
+
+#include "ns3/buffer.h"
+#include "ipv4-address.h"
+#include "address.h"
+#include "mac48-address.h"
+
+namespace ns3 {
+
+void WriteTo (Buffer::Iterator &i, Ipv4Address ad);
+void WriteTo (Buffer::Iterator &i, const Address &ad);
+void WriteTo (Buffer::Iterator &i, Mac48Address ad);
+
+void ReadFrom (Buffer::Iterator &i, Ipv4Address &ad);
+void ReadFrom (Buffer::Iterator &i, Address &ad, uint32_t len);
+void ReadFrom (Buffer::Iterator &i, Mac48Address &ad);
+
+};
+
+#endif /* ADDRESS_UTILS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/address.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,164 @@
+#include "ns3/assert.h"
+#include "address.h"
+#include <iostream>
+#include <iomanip>
+
+namespace ns3 {
+
+Address::Address ()
+  : m_type (0),
+    m_len (0)
+{
+  memset (m_data, 0, m_len);
+}
+
+Address::Address (uint8_t type, const uint8_t *buffer, uint8_t len)
+  : m_type (type),
+    m_len (len)
+{
+  NS_ASSERT (m_len <= MAX_SIZE);
+  memset (m_data, 0, m_len);
+  memcpy (m_data, buffer, m_len);
+}
+Address::Address (const Address & address)
+  : m_type (address.m_type),
+    m_len (address.m_len)
+{
+  NS_ASSERT (m_len <= MAX_SIZE);
+  memset (m_data, 0, m_len);
+  memcpy (m_data, address.m_data, m_len);
+}
+Address &
+Address::operator = (const Address &address)
+{
+  NS_ASSERT (m_len <= MAX_SIZE);
+  m_type = address.m_type;
+  m_len = address.m_len;
+  NS_ASSERT (m_len <= MAX_SIZE);
+  memset (m_data, 0, m_len);
+  memcpy (m_data, address.m_data, m_len);
+  return *this;
+}
+
+bool
+Address::IsInvalid (void) const
+{
+  return m_len == 0 && m_type == 0;
+}
+
+uint8_t 
+Address::GetLength (void) const
+{
+  NS_ASSERT (m_len <= MAX_SIZE);
+  return m_len;
+}
+uint32_t
+Address::CopyTo (uint8_t buffer[MAX_SIZE]) const
+{
+  NS_ASSERT (m_len <= MAX_SIZE);
+  memcpy (buffer, m_data, m_len);
+  return m_len;
+}
+uint32_t
+Address::CopyAllTo (uint8_t *buffer, uint8_t len) const
+{
+  NS_ASSERT (len >= m_len + 2);
+  buffer[0] = m_type;
+  buffer[1] = m_len;
+  memcpy (buffer + 2, m_data, m_len);
+  return m_len + 2;
+}
+
+uint32_t
+Address::CopyFrom (const uint8_t *buffer, uint8_t len)
+{
+  NS_ASSERT (len <= MAX_SIZE);
+  memcpy (m_data, buffer, len);
+  m_len = len;
+  return m_len;
+}
+uint32_t
+Address::CopyAllFrom (const uint8_t *buffer, uint8_t len)
+{
+  NS_ASSERT (len >= 2);
+  m_type = buffer[0];
+  m_len = buffer[1];
+  NS_ASSERT (len >= m_len + 2);
+  memcpy (m_data, buffer + 2, m_len);
+  return m_len + 2;
+}
+bool 
+Address::CheckCompatible (uint8_t type, uint8_t len) const
+{
+  NS_ASSERT (len <= MAX_SIZE);
+  return m_len == len && (m_type == type || m_type == 0);
+}
+bool 
+Address::IsMatchingType (uint8_t type) const
+{
+  return m_type == type;
+}
+
+uint8_t 
+Address::Register (void)
+{
+  static uint8_t type = 1;
+  type++;
+  return type;
+}
+
+bool operator == (const Address &a, const Address &b)
+{
+  NS_ASSERT (a.m_type == b.m_type || 
+	     a.m_type == 0 || 
+	     b.m_type == 0);
+  NS_ASSERT (a.GetLength() == b.GetLength());  
+  return memcmp (a.m_data, b.m_data, a.m_len) == 0;
+}
+bool operator != (const Address &a, const Address &b)
+{
+  return !(a == b);
+}
+bool operator < (const Address &a, const Address &b)
+{
+  NS_ASSERT (a.m_type == b.m_type  || 
+	     a.m_type == 0 || 
+	     b.m_type == 0);
+  NS_ASSERT (a.GetLength() == b.GetLength());
+  for (uint8_t i = 0; i < a.GetLength(); i++) 
+    {
+      if (a.m_data[i] < b.m_data[i]) 
+	{
+	  return true;
+	} 
+      else if (a.m_data[i] > b.m_data[i]) 
+	{
+	  return false;
+	}
+    }
+  return false;
+}
+
+std::ostream& operator<< (std::ostream& os, const Address & address)
+{
+  if (address.m_len == 0) 
+    {
+      os << "NULL-ADDRESS";
+      return os;
+    }
+  os.setf (std::ios::hex, std::ios::basefield);
+  os.fill('0');
+  for (uint8_t i=0; i < (address.m_len-1); i++) 
+    {
+      os << std::setw(2) << (uint32_t)address.m_data[i] << ":";
+    }
+  // Final byte not suffixed by ":"
+  os << std::setw(2) << (uint32_t)address.m_data[address.m_len-1];
+  os.setf (std::ios::dec, std::ios::basefield);
+  os.fill(' ');
+  return os;
+}
+
+
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/address.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,172 @@
+#ifndef ADDRESS_H
+#define ADDRESS_H
+
+#include <stdint.h>
+#include <ostream>
+
+namespace ns3 {
+
+/**
+ * \brief a polymophic address class
+ *
+ * This class is very similar in design and spirit to the BSD sockaddr
+ * structure: they are both used to hold multiple types of addresses
+ * together with the type of the address.
+ *
+ * A new address class defined by a user needs to:
+ *   - allocate a type id with Address::Register
+ *   - provide a method to convert his new address to an Address 
+ *     instance. This method is typically a member method named ConvertTo:
+ *     Address MyAddress::ConvertTo (void) const;
+ *   - provide a method to convert an Address instance back to
+ *     an instance of his new address type. This method is typically
+ *     a static member method of his address class named ConvertFrom:
+ *     static MyAddress MyAddress::ConvertFrom (const Address &address);
+ *   - the ConvertFrom method is expected to check that the type of the
+ *     input Address instance is compatible with its own type.
+ *
+ * Typical code to create a new class type looks like:
+ * \code
+ * // this class represents addresses which are 2 bytes long.
+ * class MyAddress
+ * {
+ * public:
+ *   Address ConvertTo (void) const;
+ *   static MyAddress ConvertFrom (void);
+ * private:
+ *   static uint8_t GetType (void);
+ * };
+ *
+ * Address MyAddress::ConvertTo (void) const
+ * {
+ *   return Address (GetType (), m_buffer, 2);
+ * }
+ * MyAddress MyAddress::ConvertFrom (const Address &address)
+ * {
+ *   MyAddress ad;
+ *   NS_ASSERT (address.CheckCompatible (GetType (), 2));
+ *   address.CopyTo (ad.m_buffer, 2);
+ *   return ad;
+ * }
+ * uint8_t MyAddress::GetType (void)
+ * {
+ *   static uint8_t type = Address::Register ();
+ *   return type;
+ * }
+ * \endcode
+ */
+class Address 
+{
+public:
+  enum {
+    /**
+     * The maximum size of a byte buffer which
+     * can be stored in an Address instance.
+     */
+    MAX_SIZE = 30
+  };
+
+  /**
+   * Create an invalid address
+   */
+  Address ();
+  /**
+   * \param type the type of the Address to create
+   * \param buffer a pointer to a buffer of bytes which hold
+   *        a serialized representation of the address in network
+   *        byte order.
+   * \param len the length of the buffer.
+   * 
+   * Create an address from a type and a buffer. This constructor
+   * is typically invoked from the conversion functions of various
+   * address types when they have to convert themselves to an 
+   * Address instance.
+   */
+  Address (uint8_t type, const uint8_t *buffer, uint8_t len);
+  Address (const Address & address);
+  Address &operator = (const Address &address);
+
+  /**
+   * \returns true if this address is invalid, false otherwise.
+   *
+   * An address is invalid if and only if it was created
+   * through the default constructor and it was never
+   * re-initialized.
+   */
+  bool IsInvalid (void) const;
+  /**
+   * \returns the length of the underlying address.
+   */
+  uint8_t GetLength (void) const;
+  /**
+   * \param buffer buffer to copy the address bytes to.
+   * \returns the number of bytes copied.
+   */
+  uint32_t CopyTo (uint8_t buffer[MAX_SIZE]) const;
+  /**
+   * \param buffer buffer to copy the whole address data structure to
+   * \param len the size of the buffer
+   * \returns the number of bytes copied.
+   */
+  uint32_t CopyAllTo (uint8_t *buffer, uint8_t len) const;
+  /**
+   * \param buffer pointer to a buffer of bytes which contain
+   *        a serialized representation of the address in network
+   *        byte order.
+   * \param len length of buffer
+   * \returns the number of bytes copied.
+   *
+   * Copy the input buffer to the internal buffer of this address 
+   * instance.
+   */
+  uint32_t CopyFrom (const uint8_t *buffer, uint8_t len);
+  /**
+   * \param buffer pointer to a buffer of bytes which contain
+   *        a copy of all the members of this Address class.
+   * \param len the length of the buffer
+   * \returns the number of bytes copied.
+   */
+  uint32_t CopyAllFrom (const uint8_t *buffer, uint8_t len);
+  /**
+   * \param type a type id as returned by Address::Register
+   * \param len the length associated to this type id.
+   *
+   * \returns true if the type of the address stored internally
+   * is compatible with the requested type, false otherwise.
+   */
+  bool CheckCompatible (uint8_t type, uint8_t len) const;
+  /**
+   * \param type a type id as returned by Address::Register
+   * \returns true if the type of the address stored internally
+   * is compatible with the requested type, false otherwise.
+   *
+   * This method checks that the types are _exactly_ equal.
+   * This method is really used only by the PacketSocketAddress
+   * and there is little point in using it otherwise so, 
+   * you have been warned: DO NOT USE THIS METHOD.
+   */
+  bool IsMatchingType (uint8_t type) const;
+  /**
+   * Allocate a new type id for a new type of address.
+   * \returns a new type id.
+   */
+  static uint8_t Register (void);
+private:
+  friend bool operator == (const Address &a, const Address &b);
+  friend bool operator < (const Address &a, const Address &b);
+  friend std::ostream& operator<< (std::ostream& os, const Address & address);
+
+  uint8_t m_type;
+  uint8_t m_len;
+  uint8_t m_data[MAX_SIZE];
+};
+
+bool operator == (const Address &a, const Address &b);
+bool operator != (const Address &a, const Address &b);
+bool operator < (const Address &a, const Address &b);
+std::ostream& operator<< (std::ostream& os, const Address & address);
+
+} // namespace ns3
+
+
+#endif /* ADDRESS_H */
--- a/src/node/channel.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/channel.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -14,16 +14,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
- *
- * Author: Craig Dowell <craigdo@ee.washingon.edu>
- *
- *	Thu Feb 15 14:50:46 PST 2007 craigdo: Created.
  */
 
-#include "ns3/debug.h"
+#include "ns3/log.h"
 #include "channel.h"
 
-NS_DEBUG_COMPONENT_DEFINE ("Channel");
+NS_LOG_COMPONENT_DEFINE ("Channel");
 
 namespace ns3 {
 
@@ -32,31 +28,35 @@
 Channel::Channel ()
   : m_name("Channel")
 {
+  NS_LOG_FUNCTION;
   SetInterfaceId (Channel::iid);
-  NS_DEBUG("Channel::Channel ()");
 }
 
 Channel::Channel (std::string name)
   : m_name(name)
 {
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << name << ")");
   SetInterfaceId (Channel::iid);
-  NS_DEBUG("Channel::Channel (" << name << ")");
 }
 
 Channel::~Channel ()
 {
-  NS_DEBUG("Channel::~Channel ()");
+  NS_LOG_FUNCTION;
 }
 
   void
 Channel::SetName(std::string name)
 {
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << name << ")");
   m_name = name;
 }
 
   std::string
 Channel::GetName(void)
 {
+  NS_LOG_FUNCTION;
   return m_name;
 }
 
--- a/src/node/channel.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/channel.h	Fri Sep 28 11:59:46 2007 +0100
@@ -1,7 +1,5 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 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;
@@ -14,11 +12,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.washingon.edu>
- *
- *      Wed Feb 14 16:05:46 PST 2007 craigdo:  Created
  */
+
 #ifndef CHANNEL_H
 #define CHANNEL_H
 
@@ -41,6 +36,7 @@
 {
 public:
   static const InterfaceId iid;
+
   Channel ();
   Channel (std::string name);
 
@@ -62,8 +58,8 @@
   virtual Ptr<NetDevice> GetDevice (uint32_t i) const = 0;
 
 protected:
-  virtual ~Channel ();
-  std::string m_name;
+  virtual      ~Channel ();
+  std::string   m_name;
 
 private:
 };
--- a/src/node/drop-tail-queue.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/drop-tail-queue.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -17,10 +17,10 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#include "ns3/debug.h"
+#include "ns3/log.h"
 #include "drop-tail-queue.h"
 
-NS_DEBUG_COMPONENT_DEFINE ("DropTailQueue");
+NS_LOG_COMPONENT_DEFINE ("DropTailQueue");
 
 namespace ns3 {
 
@@ -33,38 +33,39 @@
   m_packets (),
   m_maxPackets(DTQ_NPACKETS_MAX_DEFAULT)
 {
-  NS_DEBUG("DropTailQueue::DropTailQueue ()");
+  NS_LOG_FUNCTION;
 }
 
 DropTailQueue::~DropTailQueue ()
 {
-  NS_DEBUG("DropTailQueue::~DropTailQueue ()");
+  NS_LOG_FUNCTION;
 }
 
 void 
 DropTailQueue::SetMaxPackets (uint32_t npackets)
 {
-  NS_DEBUG("DropTailQueue::SetMaxPackets (" << npackets << ")");
-
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << npackets << ")");
   m_maxPackets = npackets;
 }
 
 uint32_t 
 DropTailQueue::GetMaxPackets (void)
 {
-  NS_DEBUG("DropTailQueue::GetMaxPackets () <= " << m_maxPackets);
-
+  NS_LOG_FUNCTION;
+  NS_LOG_LOGIC ("returns " << m_maxPackets);
   return m_maxPackets;
 }
 
 bool 
 DropTailQueue::DoEnqueue (const Packet& p)
 {
-  NS_DEBUG("DropTailQueue::DoEnqueue (" << &p << ")");
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << &p << ")");
 
   if (m_packets.size () >= m_maxPackets)
     {
-      NS_DEBUG("DropTailQueue::DoEnqueue (): Queue full -- droppping pkt");
+      NS_LOG_LOGIC ("Queue full -- droppping pkt");
       Drop (p);
       return false;
     }
@@ -76,18 +77,19 @@
 bool
 DropTailQueue::DoDequeue (Packet& p)
 {
-  NS_DEBUG("DropTailQueue::DoDequeue (" << &p << ")");
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << &p << ")");
 
   if (m_packets.empty()) 
     {
-      NS_DEBUG("DropTailQueue::DoDequeue (): Queue empty");
+      NS_LOG_LOGIC ("Queue empty");
       return false;
     }
 
   p = m_packets.front ();
   m_packets.pop ();
 
-  NS_DEBUG("DropTailQueue::DoDequeue (): Popped " << &p << " <= true");
+  NS_LOG_LOGIC ("Popped " << &p);
 
   return true;
 }
@@ -95,11 +97,12 @@
 bool
 DropTailQueue::DoPeek (Packet& p)
 {
-  NS_DEBUG("DropTailQueue::DoPeek (" << &p << ")");
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << &p << ")");
 
   if (m_packets.empty()) 
     {
-      NS_DEBUG("DropTailQueue::DoPeek (): Queue empty");
+      NS_LOG_LOGIC ("Queue empty");
       return false;
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/ethernet-header.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,171 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2005 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
+ * 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+ */
+
+#include <iomanip>
+#include <iostream>
+#include "ns3/assert.h"
+#include "ns3/log.h"
+#include "ns3/header.h"
+#include "ethernet-header.h"
+#include "address-utils.h"
+
+NS_LOG_COMPONENT_DEFINE ("EthernetHeader");
+
+namespace ns3 {
+
+NS_HEADER_ENSURE_REGISTERED (EthernetHeader);
+
+uint32_t
+EthernetHeader::GetUid (void)
+{
+  static uint32_t uid = AllocateUid<EthernetHeader> ("EthernetHeader.ns3");
+  return uid;
+}
+
+EthernetHeader::EthernetHeader (bool hasPreamble)
+  : m_enPreambleSfd (hasPreamble),
+    m_lengthType (0)
+{}
+
+EthernetHeader::EthernetHeader ()
+  : m_enPreambleSfd (false),
+    m_lengthType (0)
+{}
+
+void 
+EthernetHeader::SetLengthType (uint16_t lengthType)
+{
+  m_lengthType = lengthType;
+}
+uint16_t 
+EthernetHeader::GetLengthType (void) const
+{
+  return m_lengthType;
+}
+
+void 
+EthernetHeader::SetPreambleSfd (uint64_t preambleSfd)
+{
+  m_preambleSfd = preambleSfd;
+}
+uint64_t 
+EthernetHeader::GetPreambleSfd (void) const
+{
+  return m_preambleSfd;
+}
+
+void 
+EthernetHeader::SetSource (Mac48Address source)
+{
+  m_source = source;
+}
+Mac48Address
+EthernetHeader::GetSource (void) const
+{
+  return m_source;
+}
+
+void 
+EthernetHeader::SetDestination (Mac48Address dst)
+{
+  m_destination = dst;
+}
+Mac48Address
+EthernetHeader::GetDestination (void) const
+{
+  return m_destination;
+}
+
+ethernet_header_t 
+EthernetHeader::GetPacketType (void) const
+{
+  return LENGTH;
+}
+
+uint32_t 
+EthernetHeader::GetHeaderSize (void) const
+{
+  return GetSerializedSize();
+}
+
+std::string
+EthernetHeader::GetName (void) const
+{
+  return "ETHERNET";
+}
+
+void 
+EthernetHeader::Print (std::ostream &os) const
+{
+  // ethernet, right ?
+  if (m_enPreambleSfd)
+    {
+      os << " preamble/sfd=" << m_preambleSfd << ",";
+    }
+
+  os << " length/type=0x" << std::hex << m_lengthType << std::dec
+     << ", source=" << m_source
+     << ", destination=" << m_destination;
+}
+uint32_t 
+EthernetHeader::GetSerializedSize (void) const
+{
+  if (m_enPreambleSfd)
+    {
+      return PREAMBLE_SIZE + LENGTH_SIZE + 2*MAC_ADDR_SIZE;
+    } 
+  else 
+    {
+      return LENGTH_SIZE + 2*MAC_ADDR_SIZE;
+    }
+}
+
+void
+EthernetHeader::Serialize (Buffer::Iterator start) const
+{
+  Buffer::Iterator i = start;
+  
+  if (m_enPreambleSfd)
+    {
+      i.WriteU64(m_preambleSfd);
+    }
+  WriteTo (i, m_destination);
+  WriteTo (i, m_source);
+  i.WriteU16 (m_lengthType);
+}
+uint32_t
+EthernetHeader::Deserialize (Buffer::Iterator start)
+{
+  Buffer::Iterator i = start;
+
+  if (m_enPreambleSfd)
+    {
+      m_enPreambleSfd = i.ReadU64 ();
+    }
+
+  ReadFrom (i, m_destination);
+  ReadFrom (i, m_source);
+  m_lengthType = i.ReadU16 ();
+
+  return GetSerializedSize ();
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/ethernet-header.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,129 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise
+ * 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
+ * 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+ */
+
+#ifndef ETHERNET_HEADER_H
+#define ETHERNET_HEADER_H
+
+#include "ns3/header.h"
+#include <string>
+#include "ns3/mac48-address.h"
+
+namespace ns3 {
+
+  /**
+   * Types of ethernet packets. Indicates the type of the current
+   * header.
+   */
+  enum ethernet_header_t {
+    LENGTH,   /**< Basic ethernet packet, no tags, type/length field
+                 indicates packet length or IP/ARP packet */
+    VLAN,     /**< Single tagged packet. Header includes VLAN tag */
+    QINQ      /**< Double tagged packet. Header includes two VLAN tags */
+  };
+/**
+ * \brief Packet header for Ethernet
+ *
+ * This class can be used to add a header to an ethernet packet that
+ * will specify the source and destination addresses and the length of
+ * the packet. Eventually the class will be improved to also support
+ * VLAN tags in packet headers.
+ */
+class EthernetHeader : public Header 
+{
+public:
+  static uint32_t GetUid (void);
+
+  /**
+   * \brief Construct a null ethernet header
+   * \param hasPreamble if true, insert and remove an ethernet preamble from the
+   *       packet, if false, does not insert and remove it.
+   */
+  EthernetHeader (bool hasPreamble);
+  /**
+   * \brief Construct a null ethernet header
+   * By default, does not add or remove an ethernet preamble
+   */
+  EthernetHeader ();
+  /**
+   * \param size The size of the payload in bytes
+   */
+  void SetLengthType (uint16_t size);
+  /**
+   * \param source The source address of this packet
+   */
+  void SetSource (Mac48Address source);
+  /**
+   * \param destination The destination address of this packet.
+   */
+  void SetDestination (Mac48Address destination);
+  /**
+   * \param preambleSfd The value that the preambleSfd field should take
+   */
+  void SetPreambleSfd (uint64_t preambleSfd);
+  /**
+   * \return The size of the payload in bytes
+   */
+  uint16_t GetLengthType (void) const;
+  /**
+   * \return The type of packet (only basic Ethernet is currently supported)
+   */
+  ethernet_header_t GetPacketType (void) const;
+  /**
+   * \return The source address of this packet
+   */
+  Mac48Address GetSource (void) const;
+  /**
+   * \return The destination address of this packet
+   */
+  Mac48Address GetDestination (void) const;  
+  /**
+   * \return The value of the PreambleSfd field
+   */
+  uint64_t GetPreambleSfd () const;
+  /**
+   * \return The size of the header
+   */
+  uint32_t GetHeaderSize() const;
+
+  std::string GetName (void) const;
+  void Print (std::ostream &os) const;
+  uint32_t GetSerializedSize (void) const;
+  void Serialize (Buffer::Iterator start) const;
+  uint32_t Deserialize (Buffer::Iterator start);
+private:
+  static const int PREAMBLE_SIZE = 8; /// size of the preamble_sfd header field
+  static const int LENGTH_SIZE = 2;   /// size of the length_type header field
+  static const int MAC_ADDR_SIZE = 6; /// size of src/dest addr header fields
+
+  /**
+   * If false, the preamble/sfd are not serialised/deserialised.
+   */
+  bool m_enPreambleSfd;
+  uint64_t m_preambleSfd;     /// Value of the Preamble/SFD fields
+  uint16_t m_lengthType;      /// Length or type of the packet
+  Mac48Address m_source;        /// Source address
+  Mac48Address m_destination;   /// Destination address
+};
+
+}; // namespace ns3
+
+
+#endif /* ETHERNET_HEADER_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/ethernet-trailer.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,130 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2005 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
+ * 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+ */
+
+#include "ns3/assert.h"
+#include "ns3/log.h"
+#include "ns3/trailer.h"
+#include "ethernet-trailer.h"
+
+NS_LOG_COMPONENT_DEFINE ("EthernetTrailer");
+
+namespace ns3 {
+
+NS_TRAILER_ENSURE_REGISTERED (EthernetTrailer);
+
+bool EthernetTrailer::m_calcFcs = false;
+
+uint32_t
+EthernetTrailer::GetUid (void)
+{
+  static uint32_t uid = AllocateUid<EthernetTrailer> ("EthernetTrailer.ns3");
+  return uid;
+}
+
+EthernetTrailer::EthernetTrailer ()
+{
+  Init();
+}
+
+void EthernetTrailer::Init()
+{
+  m_fcs = 0;
+}
+
+void 
+EthernetTrailer::EnableFcs (bool enable)
+{
+  m_calcFcs = enable;
+}
+
+bool
+EthernetTrailer::CheckFcs (const Packet& p) const
+{
+  if (!m_calcFcs)
+    {
+      return true;
+    } else {
+      NS_LOG_WARN ("FCS calculation is not yet enabled");
+      return false;
+    }
+}
+
+void
+EthernetTrailer::CalcFcs (const Packet& p)
+{
+  NS_LOG_WARN ("FCS calculation is not yet enabled");
+}
+
+void
+EthernetTrailer::SetFcs (uint32_t fcs)
+{
+  m_fcs = fcs;
+}
+
+uint32_t
+EthernetTrailer::GetFcs (void)
+{
+  return m_fcs;
+}
+
+uint32_t
+EthernetTrailer::GetTrailerSize (void) const
+{
+  return GetSerializedSize();
+}
+std::string
+EthernetTrailer::GetName (void) const
+{
+  return "ETHERNET";
+}
+
+void 
+EthernetTrailer::Print (std::ostream &os) const
+{
+  os << " fcs=" << m_fcs;
+}
+uint32_t 
+EthernetTrailer::GetSerializedSize (void) const
+{
+  return 4;
+}
+
+void
+EthernetTrailer::Serialize (Buffer::Iterator end) const
+{
+  Buffer::Iterator i = end;
+  i.Prev(GetSerializedSize());
+  
+  i.WriteU32 (m_fcs);
+}
+uint32_t
+EthernetTrailer::Deserialize (Buffer::Iterator end)
+{
+  Buffer::Iterator i = end;
+  uint32_t size = GetSerializedSize();
+  i.Prev(size);
+
+  m_fcs = i.ReadU32 ();
+
+  return size;
+}
+
+}; // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/ethernet-trailer.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,108 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise
+ * 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
+ * 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+ */
+
+#ifndef ETHERNET_TRAILER_H
+#define ETHERNET_TRAILER_H
+
+#include "ns3/trailer.h"
+#include "ns3/packet.h"
+#include <string>
+
+namespace ns3 {
+/**
+ * \brief Packet trailer for Ethernet
+ *
+ * This class can be used to add and verify the FCS at the end of an
+ * ethernet packet. The actual FCS functionality is not yet coded and
+ * so this acts more as a placeholder.
+ */
+class EthernetTrailer : public Trailer 
+{
+public:
+  static uint32_t GetUid (void);
+
+  /**
+   * \brief Construct a null ethernet trailer
+   */
+  EthernetTrailer ();
+
+  /**
+   * \brief Enable or disabled FCS checking and calculations
+   * \param enable If true, enables FCS calculations.
+   */
+  static void EnableFcs (bool enable);
+  /**
+   * \brief Updates the Fcs Field to the correct FCS
+   * \param p Reference to a packet on which the FCS should be
+   * calculated. The packet should not currently contain an FCS
+   * trailer.
+   */
+  void CalcFcs (const Packet& p);
+  /**
+   * \brief Sets the FCS to a new value
+   * \param fcs New FCS value
+   */
+  void SetFcs (uint32_t fcs);
+  /**
+   * \return the FCS contained in this trailer
+   */
+  uint32_t GetFcs ();
+
+  /**
+   * \param p Reference to the packet on which the FCS should be
+   * calculated. The packet should not contain an FCS trailer.
+   * \return Returns true if the packet fcs is correct, false otherwise.
+   *
+   * If FCS checking is disabled, this method will always
+   * return true.
+   */
+  bool CheckFcs (const Packet& p) const;
+
+  /**
+   *\return Returns the size of the trailer
+   */ 
+  uint32_t GetTrailerSize() const;
+
+  std::string GetName (void) const;
+  void Print (std::ostream &os) const;
+  uint32_t GetSerializedSize (void) const;
+  void Serialize (Buffer::Iterator end) const;
+  uint32_t Deserialize (Buffer::Iterator end);
+private:
+
+  /**
+   * Initializes the trailer parameters during construction.
+   */
+  void Init (void);
+
+  /**
+   * Enabled FCS calculations. If false, fcs is set to 0 and checkFCS
+   * returns true.
+   */
+  static bool m_calcFcs;
+  uint32_t m_fcs; /// Value of the fcs contained in the trailer
+
+};
+
+} // namespace ns3
+
+
+#endif /* ETHERNET_TRAILER_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/inet-socket-address.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,106 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2005 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
+ * 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 "inet-socket-address.h"
+#include "ns3/assert.h"
+
+namespace ns3 {
+
+InetSocketAddress::InetSocketAddress (Ipv4Address ipv4, uint16_t port)
+  : m_ipv4 (ipv4),
+    m_port (port)
+{}
+InetSocketAddress::InetSocketAddress (Ipv4Address ipv4)
+  : m_ipv4 (ipv4),
+    m_port (0)
+{}
+InetSocketAddress::InetSocketAddress (const char *ipv4, uint16_t port)
+  : m_ipv4 (Ipv4Address (ipv4)),
+    m_port (port)
+{}
+InetSocketAddress::InetSocketAddress (const char * ipv4)
+  : m_ipv4 (Ipv4Address (ipv4)),
+    m_port (0)
+{}
+InetSocketAddress::InetSocketAddress (uint16_t port)
+  : m_ipv4 (Ipv4Address::GetAny ()),
+    m_port (port)
+{}
+uint16_t 
+InetSocketAddress::GetPort (void) const
+{
+  return m_port;
+}
+Ipv4Address 
+InetSocketAddress::GetIpv4 (void) const
+{
+  return m_ipv4;
+}
+
+void 
+InetSocketAddress::SetPort (uint16_t port)
+{
+  m_port = port;
+}
+void 
+InetSocketAddress::SetIpv4 (Ipv4Address address)
+{
+  m_ipv4 = address;
+}
+
+bool 
+InetSocketAddress::IsMatchingType (const Address &address)
+{
+  return address.CheckCompatible (GetType (), 6);
+}
+
+InetSocketAddress::operator Address () const
+{
+  return ConvertTo ();
+}
+
+Address 
+InetSocketAddress::ConvertTo (void) const
+{
+  uint8_t buf[6];
+  m_ipv4.Serialize (buf);
+  buf[4] = m_port & 0xff;
+  buf[5] = (m_port >> 8) & 0xff;
+  return Address (GetType (), buf, 6);
+}
+InetSocketAddress 
+InetSocketAddress::ConvertFrom (const Address &address)
+{
+  NS_ASSERT (address.CheckCompatible (GetType (), 6));
+  uint8_t buf[6];
+  address.CopyTo (buf);
+  Ipv4Address ipv4 = Ipv4Address::Deserialize (buf);
+  uint16_t port = buf[4] | (buf[5] << 8);
+  return InetSocketAddress (ipv4, port);
+}
+uint8_t 
+InetSocketAddress::GetType (void)
+{
+  static uint8_t type = Address::Register ();
+  return type;
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/inet-socket-address.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,117 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2005 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
+ * 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 INET_SOCKET_ADDRESS_H
+#define INET_SOCKET_ADDRESS_H
+
+#include "address.h"
+#include "ipv4-address.h"
+#include <stdint.h>
+
+namespace ns3 {
+
+
+/**
+ * \brief an Inet address class
+ *
+ * This class is similar to inet_sockaddr in the BSD socket
+ * API. i.e., this class holds an Ipv4Address and a port number
+ * to form an ipv4 transport endpoint.
+ */
+class InetSocketAddress
+{
+public:
+  /**
+   * \param ipv4 the ipv4 address
+   * \param port the port number
+   */
+  InetSocketAddress (Ipv4Address ipv4, uint16_t port);
+  /**
+   * \param ipv4 the ipv4 address
+   *
+   * The port number is set to zero by default.
+   */
+  InetSocketAddress (Ipv4Address ipv4);
+  /**
+   * \param port the port number
+   *
+   * The ipv4 address is set to the "Any" address by default.
+   */
+  InetSocketAddress (uint16_t port);
+  /**
+   * \param ipv4 string which represents an ipv4 address
+   * \param port the port number
+   */
+  InetSocketAddress (const char *ipv4, uint16_t port);
+  /**
+   * \param ipv4 string which represents an ipv4 address
+   *
+   * The port number is set to zero.
+   */
+  InetSocketAddress (const char *ipv4);
+  /**
+   * \returns the port number
+   */
+  uint16_t GetPort (void) const;
+  /**
+   * \returns the ipv4 address
+   */
+  Ipv4Address GetIpv4 (void) const;
+
+  /**
+   * \param port the new port number.
+   */
+  void SetPort (uint16_t port);
+  /**
+   * \param address the new ipv4 address
+   */
+  void SetIpv4 (Ipv4Address address);
+
+  /**
+   * \returns true if the address matches, false otherwise.
+   */
+  static bool IsMatchingType (const Address &address);
+
+  /**
+   * \returns an Address instance which represents this
+   * InetSocketAddress instance.
+   */
+  operator Address () const;
+
+  /**
+   * \param address the Address instance to convert from.
+   *
+   * Returns an InetSocketAddress which corresponds to the input
+   * Address
+   */
+  static InetSocketAddress ConvertFrom (const Address &address);
+private:
+  Address ConvertTo (void) const;
+
+  static uint8_t GetType (void);
+  Ipv4Address m_ipv4;
+  uint16_t m_port;
+};
+
+} // namespace ns3
+
+
+#endif /* INET_SOCKET_ADDRESS_H */
--- a/src/node/ipv4-address.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/ipv4-address.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -18,12 +18,12 @@
  *
  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
  */
-#include "ns3/debug.h"
 
-NS_DEBUG_COMPONENT_DEFINE("Ipv4Address");
+#include "ns3/log.h"
+#include "ipv4-address.h"
+#include "ns3/assert.h"
 
-#include "ipv4-address.h"
-
+NS_LOG_COMPONENT_DEFINE("Ipv4Address");
 
 namespace ns3 {
 
@@ -99,6 +99,11 @@
 {
   m_mask = value;
 }
+uint32_t 
+Ipv4Mask::GetInverse (void) const
+{
+  return ~m_mask;
+}
 
 void 
 Ipv4Mask::Print (std::ostream &os) const
@@ -135,6 +140,17 @@
   m_address = AsciiToIpv4Host (address);
 }
 
+void
+Ipv4Address::Set (uint32_t address)
+{
+  m_address = address;
+}
+void
+Ipv4Address::Set (char const *address)
+{
+  m_address = AsciiToIpv4Host (address);
+}
+
 bool 
 Ipv4Address::IsEqual (Ipv4Address other) const
 {
@@ -145,11 +161,38 @@
   }
 }
 
-bool 
-Ipv4Address::IsMulticast (void)
+Ipv4Address
+Ipv4Address::CombineMask (Ipv4Mask const &mask) const
+{
+  return Ipv4Address (GetHostOrder () & mask.GetHostOrder ());
+}
+
+Ipv4Address 
+Ipv4Address::GetSubnetDirectedBroadcast (Ipv4Mask const &mask) const
+{
+  return Ipv4Address (GetHostOrder () | mask.GetInverse ());
+}
+
+bool
+Ipv4Address::IsSubnetDirectedBroadcast (Ipv4Mask const &mask) const
 {
-  // XXX
-  return false;
+  return ( (GetHostOrder () | mask.GetInverse ()) == GetHostOrder () );
+}
+
+bool
+Ipv4Address::IsBroadcast (void) const
+{
+  return (m_address == 0xffffffffU);
+}
+
+bool 
+Ipv4Address::IsMulticast (void) const
+{
+//
+// Multicast addresses are defined as ranging from 224.0.0.0 through 
+// 239.255.255.255 (which is E0000000 through EFFFFFFF in hex).
+//
+  return (m_address >= 0xe0000000 && m_address <= 0xefffffff);
 }
 
 uint32_t
@@ -170,6 +213,20 @@
   buf[2] = (m_address >> 8) & 0xff;
   buf[3] = (m_address >> 0) & 0xff;
 }
+Ipv4Address 
+Ipv4Address::Deserialize (const uint8_t buf[4])
+{
+  Ipv4Address ipv4;
+  ipv4.m_address = 0;
+  ipv4.m_address |= buf[0];
+  ipv4.m_address <<= 8;
+  ipv4.m_address |= buf[1];
+  ipv4.m_address <<= 8;
+  ipv4.m_address |= buf[2];
+  ipv4.m_address <<= 8;
+  ipv4.m_address |= buf[3];
+  return ipv4;
+}
 
 void 
 Ipv4Address::Print (std::ostream &os) const
@@ -180,7 +237,39 @@
      << ((m_address >> 0) & 0xff);
 }
 
+bool 
+Ipv4Address::IsMatchingType (const Address &address)
+{
+  return address.CheckCompatible (GetType (), 4);
+}
+Ipv4Address::operator Address ()
+{
+  return ConvertTo ();
+}
 
+Address 
+Ipv4Address::ConvertTo (void) const
+{
+  uint8_t buf[4];
+  Serialize (buf);
+  return Address (GetType (), buf, 4);
+}
+
+Ipv4Address
+Ipv4Address::ConvertFrom (const Address &address)
+{
+  NS_ASSERT (address.CheckCompatible (GetType (), 4));
+  uint8_t buf[4];
+  address.CopyTo (buf);
+  return Deserialize (buf);
+}
+
+uint8_t 
+Ipv4Address::GetType (void)
+{
+  static uint8_t type = Address::Register ();
+  return type;
+}
 
 Ipv4Address 
 Ipv4Address::GetZero (void)
--- a/src/node/ipv4-address.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/ipv4-address.h	Fri Sep 28 11:59:46 2007 +0100
@@ -24,9 +24,12 @@
 
 #include <stdint.h>
 #include <ostream>
+#include "address.h"
 
 namespace ns3 {
 
+class Ipv4Mask;
+
 /** Ipv4 addresses are stored in host order in
   * this class.
   */
@@ -50,6 +53,22 @@
   Ipv4Address (char const *address);
   
   /**
+   * input address is in host order.
+   * \param address The host order 32-bit address
+   */
+  void Set (uint32_t address);
+  /** 
+    * \brief Sets an Ipv4Address by parsing a the input C-string
+    *
+    * Input address is in format:
+    * hhh.xxx.xxx.lll
+    * where h is the high byte and l the
+    * low byte
+    * \param address C-string containing the address as described above
+    */
+  void Set (char const *address);
+
+  /**
    * \brief Comparison operation between two Ipv4Addresses
    * \param other address to which to compare this address
    * \return True if the addresses are equal. False otherwise.
@@ -68,11 +87,19 @@
   void SetHostOrder (uint32_t ip);
   /**
    * Serialize this address to a 4-byte buffer
+   *
    * \param buf output buffer to which this address gets overwritten with this
    * Ipv4Address
    */
   void Serialize (uint8_t buf[4]) const;
   /**
+   * \param buf buffer to read address from
+   * \returns an Ipv4Address
+   * 
+   * The input address is expected to be in network byte order format.
+   */
+  static Ipv4Address Deserialize (const uint8_t buf[4]);
+  /**
    * \brief Print this address to the given output stream
    *
    * The print format is in the typical "192.168.1.1"
@@ -80,14 +107,40 @@
    */
   void Print (std::ostream &os) const;
 
-  bool IsBroadcast (void);
-  bool IsMulticast (void);
+  bool IsBroadcast (void) const;
+  bool IsMulticast (void) const;
+  /**
+   * \brief Combine this address with a network mask
+   *
+   * This method returns an IPv4 address that is this address combined
+   * (bitwise and) with a network mask, yielding an IPv4 network
+   * address.
+   *
+   * \param mask a network mask 
+   */
+  Ipv4Address CombineMask (Ipv4Mask const &mask) const;
+  /**
+   * \brief Generate subnet-directed broadcast address corresponding to mask
+   *
+   * The subnet-directed broadcast address has the host bits set to all
+   * ones.
+   *
+   * \param mask a network mask 
+   */
+  Ipv4Address GetSubnetDirectedBroadcast (Ipv4Mask const &mask) const;
+  bool IsSubnetDirectedBroadcast (Ipv4Mask const &mask) const;
+
+  static bool IsMatchingType (const Address &address);
+  operator Address ();
+  static Ipv4Address ConvertFrom (const Address &address);
 
   static Ipv4Address GetZero (void);
   static Ipv4Address GetAny (void);
   static Ipv4Address GetBroadcast (void);
   static Ipv4Address GetLoopback (void);
 private:
+  Address ConvertTo (void) const;
+  static uint8_t GetType (void);
   uint32_t m_address;
 };
 
@@ -108,6 +161,10 @@
    */
   uint32_t GetHostOrder (void) const;
   void SetHostOrder (uint32_t value);
+  /**
+   * \brief Return the inverse mask in host order. 
+   */
+  uint32_t GetInverse (void) const;
 
   void Print (std::ostream &os) const;
 
--- a/src/node/ipv4-route.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/ipv4-route.cc	Fri Sep 28 11:59:46 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	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/ipv4-route.h	Fri Sep 28 11:59:46 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	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/ipv4.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -18,6 +18,9 @@
  *
  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
  */
+
+#include "ns3/assert.h" 
+#include "ns3/node.h" 
 #include "ipv4.h"
 
 namespace ns3 {
@@ -32,4 +35,61 @@
 Ipv4::~Ipv4 ()
 {}
 
+uint32_t 
+Ipv4::GetIfIndexByAddress (Ptr<Node> node, Ipv4Address a, Ipv4Mask amask)
+{
+  Ptr<Ipv4> ipv4 = node->QueryInterface<Ipv4> (Ipv4::iid);
+  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) )
+        {
+          return i;
+        }
+    }
+  // Mapping not found
+  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 
+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, "Ipv4::GetRouteToDestination:  No Ipv4 interface");
+  for (uint32_t i = 0; i < ipv4->GetNRoutes (); i++) 
+    {
+      tempRoute = ipv4->GetRoute (i);
+      // Host route found
+      if ( tempRoute.IsNetwork () == false && tempRoute.GetDest () == a ) 
+        {
+          route = tempRoute;
+          return true;
+        }
+      else if ( tempRoute.IsNetwork () && 
+                tempRoute.GetDestNetwork () == a.CombineMask(amask) )
+        {
+          route = tempRoute;
+          return true;
+        }
+      else if ( tempRoute.IsDefault () )
+        {
+          route = tempRoute;
+          return true;
+        }
+    }
+  return false;
+}
+
 } // namespace ns3
--- a/src/node/ipv4.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/ipv4.h	Fri Sep 28 11:59:46 2007 +0100
@@ -24,13 +24,126 @@
 #include <stdint.h>
 #include "ns3/ipv4-address.h"
 #include "ns3/object.h"
+#include "ns3/callback.h"
 #include "ipv4-route.h"
 
 namespace ns3 {
 
+class Node;
 class NetDevice;
 class Packet;
 class Ipv4Route;
+class Ipv4Header; // FIXME: ipv4-header.h needs to move from module
+                  // "internet-node" to module "node"
+
+/**
+ * \brief Base class for IPv4 routing protocols.
+ *
+ * This class represents the interface between the IPv4 routing core
+ * and a specific IPv4 routing protocol.  The interface is
+ * asynchronous (callback based) in order to support reactive routing
+ * protocols (e.g. AODV).
+ */
+class Ipv4RoutingProtocol : public Object
+{
+public:
+  // void (*RouteReply) (bool found, Ipv4Route route, Packet packet, Ipv4Header const &ipHeader);
+
+
+  /**
+   * \brief Callback to be invoked when route discovery is completed
+   *
+   * \param bool flag indicating whether a route was actually found;
+   * when this is false, the Ipv4Route parameter is ignored
+   *
+   * \param Ipv4Route the route found
+   *
+   * \param Packet the packet for which a route was requested; can be
+   * modified by the routing protocol
+   *
+   * \param Ipv4Header the IP header supplied to the route request
+   * method (possibly modified in case a new routing header is
+   * inserted and consequently the protocol type has to change).
+   *
+   */
+  typedef Callback<void, bool, const Ipv4Route&, Packet, const Ipv4Header&> RouteReplyCallback;
+
+  /**
+   * \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
+   *
+   * \returns true if the routing protocol should be able to get the
+   * route, false otherwise.
+   *
+   * This method is called whenever a node's IPv4 forwarding engine
+   * needs to lookup a route for a given packet and IP header.
+   *
+   * The routing protocol implementation may determine immediately it
+   * should not be handling this particular the route request.  For
+   * instance, a routing protocol may decline to search for routes for
+   * certain classes of addresses, like link-local.  In this case,
+   * RequestRoute() should return false and the routeReply callback
+   * must not be invoked.
+   *
+   * If the routing protocol implementations assumes it can provide
+   * the requested route, then it should return true, and the
+   * routeReply callback must be invoked, either immediately before
+   * returning true (synchronously), or in the future (asynchronous).
+   * The routing protocol may use any information available in the IP
+   * header and packet as routing key, although most routing protocols
+   * use only the destination address (as given by
+   * ipHeader.GetDestination ()).  The routing protocol is also
+   * allowed to add a new header to the packet, which will appear
+   * immediately after the IP header, although most routing do not
+   * insert any extra header.
+   */
+  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;
+};
+
 /**
  * \brief Access to the Ipv4 forwarding table and to the ipv4 interfaces
  *
@@ -47,7 +160,20 @@
   static const InterfaceId iid;
   Ipv4 ();
   virtual ~Ipv4 ();
-    
+
+  /**
+   * \brief Register a new routing protocol to be used in this IPv4 stack
+   * 
+   * \param routingProtocol new routing protocol implementation object
+   * \param priority priority to give to this routing protocol.
+   * Values may range between -32768 and +32767.  The priority 0
+   * corresponds to static routing table lookups, higher values have
+   * more priority.  The order by which routing protocols with the
+   * same priority value are consulted is undefined.
+   */
+  virtual void AddRoutingProtocol (Ptr<Ipv4RoutingProtocol> routingProtocol,
+                                   int16_t priority) = 0;
+  
   /**
    * \param dest destination address
    * \param nextHop address of next hop.
@@ -107,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.
@@ -127,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
    * 
@@ -177,6 +426,7 @@
    * considered valid during ipv4 forwarding.
    */
   virtual void SetUp (uint32_t i) = 0;
+
   /**
    * \param i index of ipv4 interface
    *
@@ -184,7 +434,17 @@
    * ignored during ipv4 forwarding.
    */
   virtual void SetDown (uint32_t i) = 0;
-  
+
+/**
+ * Convenience functions (Doxygen still needed)
+ *
+ * Return the ifIndex corresponding to the Ipv4Address provided.
+ */
+  static uint32_t GetIfIndexByAddress (Ptr<Node> node, 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/llc-snap-header.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/llc-snap-header.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -19,17 +19,24 @@
  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
  */
 
+#include "llc-snap-header.h"
 #include "ns3/assert.h"
-
-#include "llc-snap-header.h"
+#include <string>
 
 namespace ns3 {
 
+NS_HEADER_ENSURE_REGISTERED (LlcSnapHeader);
+
+uint32_t
+LlcSnapHeader::GetUid (void)
+{
+  static uint32_t uid = AllocateUid<LlcSnapHeader> ("LlcSnapHeader.ns3");
+  return uid;
+}
+
 LlcSnapHeader::LlcSnapHeader ()
 {}
 
-LlcSnapHeader::~LlcSnapHeader ()
-{}
 void 
 LlcSnapHeader::SetType (uint16_t type)
 {
@@ -47,18 +54,24 @@
   return 1 + 1 + 1 + 3 + 2;
 }
 
-void 
-LlcSnapHeader::PrintTo (std::ostream &os) const
+std::string
+LlcSnapHeader::GetName (void) const
 {
-  os << "(mac)"
-      << " EtherType: ";
+  return "LLCSNAP";
+}
+
+void 
+LlcSnapHeader::Print (std::ostream &os) const
+{
+  os << "(type 0x";
   os.setf (std::ios::hex, std::ios::basefield);
   os << m_etherType;
   os.setf (std::ios::dec, std::ios::basefield);
+  os << ")";
 }
 
 void
-LlcSnapHeader::SerializeTo (Buffer::Iterator start) const
+LlcSnapHeader::Serialize (Buffer::Iterator start) const
 {
   Buffer::Iterator i = start;
   uint8_t buf[] = {0xaa, 0xaa, 0x03, 0, 0, 0};
@@ -66,7 +79,7 @@
   i.WriteHtonU16 (m_etherType);
 }
 uint32_t
-LlcSnapHeader::DeserializeFrom (Buffer::Iterator start)
+LlcSnapHeader::Deserialize (Buffer::Iterator start)
 {
   Buffer::Iterator i = start;
   i.Next (5+1);
@@ -75,4 +88,4 @@
 }
 
 
-}; // namespace ns3
+} // namespace ns3
--- a/src/node/llc-snap-header.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/llc-snap-header.h	Fri Sep 28 11:59:46 2007 +0100
@@ -23,27 +23,30 @@
 #define LLC_SNAP_HEADER_H
 
 #include <stdint.h>
+#include <string>
 #include "ns3/header.h"
 
 namespace ns3 {
 
-class LlcSnapHeader : public Header {
- public:
+class LlcSnapHeader : public Header 
+{
+public:
+  static uint32_t GetUid (void);
+
   LlcSnapHeader ();
-  virtual ~LlcSnapHeader ();
-
 
   void SetType (uint16_t type);
   uint16_t GetType (void);
 
+  std::string GetName (void) const;
+  void Print (std::ostream &os) const;
+  uint32_t GetSerializedSize (void) const;
+  void Serialize (Buffer::Iterator start) const;
+  uint32_t Deserialize (Buffer::Iterator start);
 private:
-  virtual void PrintTo (std::ostream &os) const;
-  virtual uint32_t GetSerializedSize (void) const;
-  virtual void SerializeTo (Buffer::Iterator start) const;
-  virtual uint32_t DeserializeFrom (Buffer::Iterator start);
   uint16_t m_etherType;
 };
 
-}; // namespace ns3
+} // namespace ns3
 
 #endif /* LLC_SNAP_HEADER_H */
--- a/src/node/mac-address.cc	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,189 +0,0 @@
-/* -*-	Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2005 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
- * 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 <iostream>
-#include <iomanip>
-#include "ns3/assert.h"
-#include "mac-address.h"
-
-#define ASCII_a (0x41)
-#define ASCII_z (0x5a)
-#define ASCII_A (0x61)
-#define ASCII_Z (0x7a)
-#define ASCII_COLON (0x3a)
-#define ASCII_ZERO (0x30)
-
-namespace ns3 {
-
-static char
-AsciiToLowCase (char c)
-{
-  if (c >= ASCII_a && c <= ASCII_z) {
-    return c;
-  } else if (c >= ASCII_A && c <= ASCII_Z) {
-    return c + (ASCII_a - ASCII_A);
-  } else {
-    return c;
-  }
-}
-
-
-MacAddress::MacAddress () : m_len(0)
-{
-  for (int i=0; i < MacAddress::MAX_LEN; i++) 
-    {
-      m_address[i] = 0;
-    }
-}
-
-MacAddress::MacAddress (uint8_t const *address, uint8_t len)
-{
-  NS_ASSERT (len <= MacAddress::MAX_LEN);
-  for (int i=0; i < len; i++) 
-    {
-      m_address[i] = address[i];
-    }
-  for (int i=len; i < MacAddress::MAX_LEN; i++) 
-    {
-      m_address[i] = 0;
-    } 
-  m_len = len;
-}
-
-MacAddress::MacAddress (char const *str)
-{       
-  int i = 0;
-  while (*str != 0 && i < MacAddress::MAX_LEN) {
-    uint8_t byte = 0;
-    while (*str != ASCII_COLON && *str != 0) {
-      byte <<= 4;
-      char low = AsciiToLowCase (*str);
-      if (low >= ASCII_a) {
-        byte |= low - ASCII_a + 10;
-      } else {
-        byte |= low - ASCII_ZERO;
-      }
-      str++;
-    }
-    m_address[i] = byte;
-    i++;
-    if (*str == 0) {
-      break;
-    }
-    str++;
-  }
-  m_len = i;
-}
-
-MacAddress::~MacAddress ()
-{}
-
-bool 
-MacAddress::IsEqual (MacAddress other) const
-{
-    if (memcmp(other.m_address, m_address, m_len)) 
-      {
-        return false;
-      } 
-    else 
-      {
-        return true;
-      } 
-}
-
-void
-MacAddress::Print (std::ostream &os) const
-{
-    int i;
-    if (m_len == 0) 
-      {
-        os << "NULL-ADDRESS";
-        return;
-      }
-    os.setf (std::ios::hex, std::ios::basefield);
-    std::cout.fill('0');
-    for (i=0; i< (m_len-1); i++) 
-      {
-	os << std::setw(2) << (uint32_t)m_address[i] << ":";
-      }
-    // Final byte not suffixed by ":"
-    os << std::setw(2) << (uint32_t)m_address[i];
-    os.setf (std::ios::dec, std::ios::basefield);
-    std::cout.fill(' ');
-}
-
-uint8_t
-MacAddress::GetLength () const
-{
-    return m_len;
-}
-
-void
-MacAddress::Peek (uint8_t ad[MacAddress::MAX_LEN]) const
-{
-	memcpy (ad, m_address, MacAddress::MAX_LEN);
-}
-void
-MacAddress::Set (uint8_t const ad[MacAddress::MAX_LEN], uint8_t len)
-{
-	memcpy (m_address, ad, MacAddress::MAX_LEN);
-        m_len = len;
-}
-
-bool operator == (MacAddress const&a, MacAddress const&b)
-{
-	return a.IsEqual (b);
-}
-
-bool operator != (MacAddress const&a, MacAddress const&b)
-{
-	return !a.IsEqual (b);
-}
-
-bool operator < (MacAddress const&a, MacAddress const&b)
-{
-        uint8_t a_p[MacAddress::MAX_LEN];
-        uint8_t b_p[MacAddress::MAX_LEN];
-        a.Peek (a_p);
-        b.Peek (b_p);
-        NS_ASSERT (a.GetLength() == b.GetLength());
-        for (uint8_t i = 0; i < a.GetLength(); i++) 
-          {
-            if (a_p[i] < b_p[i]) 
-              {
-                return true;
-              } 
-            else if (a_p[i] > b_p[i]) 
-              {
-                return false;
-              }
-          }
-        return false;
-}
-
-std::ostream& operator<< (std::ostream& os, MacAddress const& address)
-{
-	address.Print (os);
-	return os;
-}
-
-
-}; // namespace ns3
--- a/src/node/mac-address.h	Thu Jul 19 13:17:35 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,113 +0,0 @@
-/* -*-	Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2005 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
- * 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 MAC_ADDRESS_H
-#define MAC_ADDRESS_H
-
-#include <stdint.h>
-#include <ostream>
-
-namespace ns3 {
-
-/**
- * \brief base class for Network Device addresses
- *
- * This class is a base class for different types of Network
- * Device addresses.  It generically stores an address of 
- * MAX_ADDR_LEN bytes, and provides methods to compare, print, and set
- * the address.
- */
-class MacAddress {
-public:
-  enum {
-    MAX_LEN = 32
-  };
-  /**
-   * \brief Construct a null MacAddress
-   *
-   * This MacAddress has length of zero, and is internally all zeros
-   */
-  MacAddress (void);
-  /**
-   * \brief Construct a MacAddress from a byte-array
-   *
-   * low byte should be first.
-   * \param address a byte array indicating the address
-   * \param len length, in bytes, of the address points to
-   */
-  MacAddress (uint8_t const *address, uint8_t len);
-  /**
-   * \brief Construct a MacAddress from a C-string
-   *
-   * The string should look like this:
-   * hh:xx:xx:xx:xx:ll
-   * where hh is the high byte and ll is
-   * the low byte.
-   * \param address the C-string representation of the address
-   */
-  MacAddress (char const *address);
-  ~MacAddress ();
-  
-  /**
-   * \brief Comparison operation between MacAddresses
-   * \param other The address against which to compare this one
-   * \return True if they are equal, false otherwise.
-   */   
-  bool IsEqual (MacAddress other) const;
-  /**
-   * \brief Print this MacAddress to a stream
-   *
-   * The format is colon seperated groups of two hexadecimal digits
-   * \param os The output stream desired
-   */ 
-  void Print (std::ostream &os) const;
-  
-  /**
-   * \return The length in bytes of this MacAddress
-   */
-  uint8_t GetLength() const;
-  /**
-   * \brief Copy routine to peek the contents of the MacAddress
-   *
-   * \param ad Output parameter which holds a copy of this MacAddress
-   */
-  void Peek (uint8_t ad[MAX_LEN]) const;
-  /**
-   * \brief Sets this MacAddress to a specific value
-   * \param ad byte buffer to set the MacAddress to
-   * \param len the length of the buffer
-   */
-  void Set (uint8_t const ad[MAX_LEN], uint8_t len);
-
-private:
-  uint8_t m_address[MAX_LEN];
-  uint8_t m_len;
-};
-
-bool operator == (MacAddress const&a, MacAddress const&b);
-bool operator != (MacAddress const&a, MacAddress const&b);
-bool operator < (MacAddress const&a, MacAddress const&b);
-
-std::ostream& operator<< (std::ostream& os, MacAddress const& address);
-
-}; // namespace ns3
-
-#endif /* MAC_ADDRESS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/mac48-address.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,168 @@
+/* -*-  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 "mac48-address.h"
+#include "address.h"
+#include "ns3/assert.h"
+#include <iomanip>
+#include <iostream>
+
+namespace ns3 {
+
+#define ASCII_a (0x41)
+#define ASCII_z (0x5a)
+#define ASCII_A (0x61)
+#define ASCII_Z (0x7a)
+#define ASCII_COLON (0x3a)
+#define ASCII_ZERO (0x30)
+
+static char
+AsciiToLowCase (char c)
+{
+  if (c >= ASCII_a && c <= ASCII_z) {
+    return c;
+  } else if (c >= ASCII_A && c <= ASCII_Z) {
+    return c + (ASCII_a - ASCII_A);
+  } else {
+    return c;
+  }
+}
+
+
+Mac48Address::Mac48Address ()
+{
+  memset (m_address, 0, 6);
+}
+Mac48Address::Mac48Address (const char *str)
+{
+  int i = 0;
+  while (*str != 0 && i < 6) 
+    {
+      uint8_t byte = 0;
+      while (*str != ASCII_COLON && *str != 0) 
+	{
+	  byte <<= 4;
+	  char low = AsciiToLowCase (*str);
+	  if (low >= ASCII_a) 
+	    {
+	      byte |= low - ASCII_a + 10;
+	    } 
+	  else 
+	    {
+	      byte |= low - ASCII_ZERO;
+	    }
+	  str++;
+	}
+      m_address[i] = byte;
+      i++;
+      if (*str == 0) 
+	{
+	  break;
+	}
+      str++;
+    }
+  NS_ASSERT (i == 6);
+}
+void 
+Mac48Address::CopyFrom (const uint8_t buffer[6])
+{
+  memcpy (m_address, buffer, 6);
+}
+void 
+Mac48Address::CopyTo (uint8_t buffer[6]) const
+{
+  memcpy (buffer, m_address, 6);
+}
+
+bool 
+Mac48Address::IsMatchingType (const Address &address)
+{
+  return address.CheckCompatible (GetType (), 6);
+}
+Mac48Address::operator Address ()
+{
+  return ConvertTo ();
+}
+Address 
+Mac48Address::ConvertTo (void) const
+{
+  return Address (GetType (), m_address, 6);
+}
+Mac48Address 
+Mac48Address::ConvertFrom (const Address &address)
+{
+  NS_ASSERT (address.CheckCompatible (GetType (), 6));
+  Mac48Address retval;
+  address.CopyTo (retval.m_address);
+  return retval;
+}
+Mac48Address 
+Mac48Address::Allocate (void)
+{
+  static uint64_t id = 0;
+  id++;
+  Mac48Address address;
+  address.m_address[0] = (id >> 40) & 0xff;
+  address.m_address[1] = (id >> 32) & 0xff;
+  address.m_address[2] = (id >> 24) & 0xff;
+  address.m_address[3] = (id >> 16) & 0xff;
+  address.m_address[4] = (id >> 8) & 0xff;
+  address.m_address[5] = (id >> 0) & 0xff;
+  return address;
+}
+uint8_t 
+Mac48Address::GetType (void)
+{
+  static uint8_t type = Address::Register ();
+  return type;
+}
+
+bool operator == (const Mac48Address &a, const Mac48Address &b)
+{
+  uint8_t ada[6];
+  uint8_t adb[6];
+  a.CopyTo (ada);
+  b.CopyTo (adb);
+  return memcmp (ada, adb, 6) == 0;
+}
+bool operator != (const Mac48Address &a, const Mac48Address &b)
+{
+  return ! (a == b);
+}
+
+std::ostream& operator<< (std::ostream& os, const Mac48Address & address)
+{
+  uint8_t ad[6];
+  address.CopyTo (ad);
+
+  os.setf (std::ios::hex, std::ios::basefield);
+  os.fill('0');
+  for (uint8_t i=0; i < 5; i++) 
+    {
+      os << std::setw(2) << (uint32_t)ad[i] << ":";
+    }
+  // Final byte not suffixed by ":"
+  os << std::setw(2) << (uint32_t)ad[5];
+  os.setf (std::ios::dec, std::ios::basefield);
+  os.fill(' ');
+  return os;
+}
+
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/mac48-address.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,99 @@
+/* -*-  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 EUI48_ADDRESS_H
+#define EUI48_ADDRESS_H
+
+#include <stdint.h>
+#include <ostream>
+
+namespace ns3 {
+
+class Address;
+
+/**
+ * \brief an EUI-48 address
+ *
+ * This class can contain 48 bit IEEE addresses.
+ */
+class Mac48Address
+{
+public:
+  Mac48Address ();
+  /**
+   * \param str a string representing the new Mac48Address
+   *
+   * The format of the string is "xx:xx:xx:xx:xx:xx"
+   */
+  Mac48Address (const char *str);
+
+  /**
+   * \param buffer address in network order
+   *
+   * Copy the input address to our internal buffer.
+   */
+  void CopyFrom (const uint8_t buffer[6]);
+  /**
+   * \param buffer address in network order
+   *
+   * Copy the internal address to the input buffer.
+   */
+  void CopyTo (uint8_t buffer[6]) const;
+
+  /**
+   * \returns a new Address instance
+   *
+   * Convert an instance of this class to a polymorphic Address instance.
+   */
+  operator Address ();
+  /**
+   * \param address a polymorphic address
+   * \returns a new Mac48Address from the polymorphic address
+   * 
+   * This function performs a type check and asserts if the
+   * type of the input address is not compatible with an
+   * Mac48Address.
+   */
+  static Mac48Address ConvertFrom (const Address &address);
+  /**
+   * \returns true if the address matches, false otherwise.
+   */
+  static bool IsMatchingType (const Address &address);
+  /**
+   * Allocate a new Mac48Address.
+   */
+  static Mac48Address Allocate (void);
+private:
+  /**
+   * \returns a new Address instance
+   *
+   * Convert an instance of this class to a polymorphic Address instance.
+   */
+  Address ConvertTo (void) const;
+  static uint8_t GetType (void);
+  uint8_t m_address[6];
+};
+
+bool operator == (const Mac48Address &a, const Mac48Address &b);
+bool operator != (const Mac48Address &a, const Mac48Address &b);
+std::ostream& operator<< (std::ostream& os, const Mac48Address & address);
+
+} // namespace ns3
+
+#endif /* EUI48_ADDRESS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/mac64-address.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,171 @@
+/* -*-  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 "mac64-address.h"
+#include "address.h"
+#include "ns3/assert.h"
+#include <iomanip>
+#include <iostream>
+
+namespace ns3 {
+
+#define ASCII_a (0x41)
+#define ASCII_z (0x5a)
+#define ASCII_A (0x61)
+#define ASCII_Z (0x7a)
+#define ASCII_COLON (0x3a)
+#define ASCII_ZERO (0x30)
+
+static char
+AsciiToLowCase (char c)
+{
+  if (c >= ASCII_a && c <= ASCII_z) {
+    return c;
+  } else if (c >= ASCII_A && c <= ASCII_Z) {
+    return c + (ASCII_a - ASCII_A);
+  } else {
+    return c;
+  }
+}
+
+
+Mac64Address::Mac64Address ()
+{
+  memset (m_address, 0, 8);
+}
+Mac64Address::Mac64Address (const char *str)
+{
+  int i = 0;
+  while (*str != 0 && i < 8) 
+    {
+      uint8_t byte = 0;
+      while (*str != ASCII_COLON && *str != 0) 
+	{
+	  byte <<= 4;
+	  char low = AsciiToLowCase (*str);
+	  if (low >= ASCII_a) 
+	    {
+	      byte |= low - ASCII_a + 10;
+	    } 
+	  else 
+	    {
+	      byte |= low - ASCII_ZERO;
+	    }
+	  str++;
+	}
+      m_address[i] = byte;
+      i++;
+      if (*str == 0) 
+	{
+	  break;
+	}
+      str++;
+    }
+  NS_ASSERT (i == 6);
+}
+void 
+Mac64Address::CopyFrom (const uint8_t buffer[8])
+{
+  memcpy (m_address, buffer, 8);
+}
+void 
+Mac64Address::CopyTo (uint8_t buffer[8]) const
+{
+  memcpy (buffer, m_address, 8);
+}
+
+bool 
+Mac64Address::IsMatchingType (const Address &address)
+{
+  return address.CheckCompatible (GetType (), 8);
+}
+Mac64Address::operator Address ()
+{
+  return ConvertTo ();
+}
+Mac64Address 
+Mac64Address::ConvertFrom (const Address &address)
+{
+  NS_ASSERT (address.CheckCompatible (GetType (), 8));
+  Mac64Address retval;
+  address.CopyTo (retval.m_address);
+  return retval;
+}
+Address
+Mac64Address::ConvertTo (void) const
+{
+  return Address (GetType (), m_address, 8);
+}
+
+Mac64Address 
+Mac64Address::Allocate (void)
+{
+  static uint64_t id = 0;
+  id++;
+  Mac64Address address;
+  address.m_address[0] = (id >> 56) & 0xff;
+  address.m_address[1] = (id >> 48) & 0xff;
+  address.m_address[2] = (id >> 40) & 0xff;
+  address.m_address[3] = (id >> 32) & 0xff;
+  address.m_address[4] = (id >> 24) & 0xff;
+  address.m_address[5] = (id >> 16) & 0xff;
+  address.m_address[6] = (id >> 8) & 0xff;
+  address.m_address[7] = (id >> 0) & 0xff;
+  return address;
+}
+uint8_t 
+Mac64Address::GetType (void)
+{
+  static uint8_t type = Address::Register ();
+  return type;
+}
+
+bool operator == (const Mac64Address &a, const Mac64Address &b)
+{
+  uint8_t ada[8];
+  uint8_t adb[8];
+  a.CopyTo (ada);
+  b.CopyTo (adb);
+  return memcmp (ada, adb, 8) == 0;
+}
+bool operator != (const Mac64Address &a, const Mac64Address &b)
+{
+  return ! (a == b);
+}
+
+std::ostream& operator<< (std::ostream& os, const Mac64Address & address)
+{
+  uint8_t ad[8];
+  address.CopyTo (ad);
+
+  os.setf (std::ios::hex, std::ios::basefield);
+  os.fill('0');
+  for (uint8_t i=0; i < 7; i++) 
+    {
+      os << std::setw(2) << (uint32_t)ad[i] << ":";
+    }
+  // Final byte not suffixed by ":"
+  os << std::setw(2) << (uint32_t)ad[7];
+  os.setf (std::ios::dec, std::ios::basefield);
+  os.fill(' ');
+  return os;
+}
+
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/mac64-address.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,98 @@
+/* -*-  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 EUI64_ADDRESS_H
+#define EUI64_ADDRESS_H
+
+#include <stdint.h>
+#include <ostream>
+
+namespace ns3 {
+
+class Address;
+
+/**
+ * \brief an EUI-64 address
+ *
+ * This class can contain 64 bit IEEE addresses.
+ */
+class Mac64Address
+{
+public:
+  Mac64Address ();
+  /**
+   * \param str a string representing the new Mac64Address
+   *
+   * The format of the string is "xx:xx:xx:xx:xx:xx"
+   */
+  Mac64Address (const char *str);
+
+  /**
+   * \param buffer address in network order
+   *
+   * Copy the input address to our internal buffer.
+   */
+  void CopyFrom (const uint8_t buffer[8]);
+  /**
+   * \param buffer address in network order
+   *
+   * Copy the internal address to the input buffer.
+   */
+  void CopyTo (uint8_t buffer[8]) const;
+  /**
+   * \returns a new Address instance
+   *
+   * Convert an instance of this class to a polymorphic Address instance.
+   */
+  operator Address ();
+  /**
+   * \param address a polymorphic address
+   * \returns a new Mac64Address from the polymorphic address
+   * 
+   * This function performs a type check and asserts if the
+   * type of the input address is not compatible with an
+   * Mac64Address.
+   */
+  static Mac64Address ConvertFrom (const Address &address);
+  /**
+   * \returns true if the address matches, false otherwise.
+   */
+  static bool IsMatchingType (const Address &address);
+  /**
+   * Allocate a new Mac64Address.
+   */
+  static Mac64Address Allocate (void);
+private:
+  /**
+   * \returns a new Address instance
+   *
+   * Convert an instance of this class to a polymorphic Address instance.
+   */
+  Address ConvertTo (void) const;
+  static uint8_t GetType (void);
+  uint8_t m_address[8];
+};
+
+bool operator == (const Mac64Address &a, const Mac64Address &b);
+bool operator != (const Mac64Address &a, const Mac64Address &b);
+std::ostream& operator<< (std::ostream& os, const Mac64Address & address);
+
+} // namespace ns3
+
+#endif /* EUI64_ADDRESS_H */
--- a/src/node/net-device.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/net-device.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -22,17 +22,19 @@
 #include <iostream>
 #include "ns3/assert.h"
 #include "ns3/object.h"
-
+#include "ns3/log.h"
+#include "ns3/trace-resolver.h"
 #include "channel.h"
 #include "net-device.h"
-#include "llc-snap-header.h"
 #include "node.h"
 
+NS_LOG_COMPONENT_DEFINE ("NetDevice");
+
 namespace ns3 {
 
 const InterfaceId NetDevice::iid = MakeInterfaceId ("NetDevice", Object::iid);
 
-NetDevice::NetDevice(Ptr<Node> node, const MacAddress& addr) : 
+NetDevice::NetDevice(Ptr<Node> node, const Address& addr) : 
   m_node (node), 
   m_name(""), 
   m_ifIndex (0), 
@@ -43,22 +45,27 @@
   m_isMulticast (false), 
   m_isPointToPoint (false)
 {
+  NS_LOG_FUNCTION;
   SetInterfaceId (NetDevice::iid);
   m_node->AddDevice (this);
 }
 
 NetDevice::~NetDevice ()
-{}
+{
+  NS_LOG_FUNCTION;
+}
 
-MacAddress 
+Address 
 NetDevice::GetAddress (void) const
 {
+  NS_LOG_FUNCTION;
   return m_address;
 }
 
 bool
 NetDevice::SetMtu (const uint16_t mtu) 
 {
+  NS_LOG_FUNCTION;
   m_mtu = mtu;
   return true;
 }
@@ -66,60 +73,71 @@
 uint16_t 
 NetDevice::GetMtu (void) const
 {
+  NS_LOG_FUNCTION;
   return m_mtu;
 }
 
 void
 NetDevice::SetName(const std::string name) 
 { 
+  NS_LOG_FUNCTION;
   m_name = name; 
 }
 
 std::string 
 NetDevice::GetName(void) const 
 { 
+  NS_LOG_FUNCTION;
   return m_name; 
 }
 
 void
 NetDevice::SetIfIndex(uint32_t index) 
 { 
+  NS_LOG_FUNCTION;
   m_ifIndex = index; 
 }
 
 uint32_t
 NetDevice::GetIfIndex(void) const 
 { 
+  NS_LOG_FUNCTION;
   return m_ifIndex; 
 }
 
 bool 
 NetDevice::IsLinkUp (void) const
 {
+  NS_LOG_FUNCTION;
   return m_isUp;
 }
 
 void 
 NetDevice::SetLinkChangeCallback (Callback<void> callback)
 {
+  NS_LOG_FUNCTION;
   m_linkChangeCallback = callback;
 }
 
 bool
 NetDevice::IsBroadcast (void) const
 {
+  NS_LOG_FUNCTION;
   return m_isBroadcast;
 }
-MacAddress const &
+
+Address const &
 NetDevice::GetBroadcast (void) const
 {
+  NS_LOG_FUNCTION;
   NS_ASSERT (m_isBroadcast);
   return m_broadcast;
 }
 
 void
-NetDevice::EnableBroadcast (MacAddress broadcast)
+NetDevice::EnableBroadcast (Address broadcast)
 {
+  NS_LOG_FUNCTION;
   m_isBroadcast = true;
   m_broadcast = broadcast;
 }
@@ -127,55 +145,79 @@
 void
 NetDevice::DisableBroadcast (void)
 {
+  NS_LOG_FUNCTION;
   m_isBroadcast = false;
 }
 
 bool
 NetDevice::IsMulticast (void) const
 {
+  NS_LOG_FUNCTION;
   return m_isMulticast;
 }
 
+Address 
+NetDevice::GetMulticast (void) const
+{
+  NS_LOG_FUNCTION;
+  NS_ASSERT_MSG (m_isMulticast, "NetDevice::GetMulticast (): "
+    "Invalid operation when not IsMulticast ()");
+  return m_multicast;
+}
+
+Address
+NetDevice::MakeMulticastAddress(Ipv4Address multicastGroup) const
+{
+  NS_LOG_FUNCTION;
+  NS_ASSERT_MSG (m_isMulticast, "NetDevice::GetMulticast (): "
+    "Invalid operation when not IsMulticast ()");
+  return m_multicast;
+}
+
 void
-NetDevice::EnableMulticast (void)
+NetDevice::EnableMulticast (Address multicast)
 {
+  NS_LOG_FUNCTION;
   m_isMulticast = true;
+  m_multicast = multicast;
 }
 
 void
 NetDevice::DisableMulticast (void)
 {
+  NS_LOG_FUNCTION;
   m_isMulticast = false;
 }
 
 bool
 NetDevice::IsPointToPoint (void) const
 {
+  NS_LOG_FUNCTION;
   return m_isPointToPoint;
 }
 
 void
 NetDevice::EnablePointToPoint (void)
 {
+  NS_LOG_FUNCTION;
   m_isPointToPoint = true;
 }
 
 void
 NetDevice::DisablePointToPoint (void)
 {
+  NS_LOG_FUNCTION;
   m_isPointToPoint = false;
 }
 
 // Receive packet from above
 bool 
-NetDevice::Send(Packet& p, const MacAddress& dest, uint16_t protocolNumber)
+NetDevice::Send(const Packet& p, const Address& dest, uint16_t protocolNumber)
 {
+  NS_LOG_FUNCTION;
   if (m_isUp)
     {
-      LlcSnapHeader llc;
-      llc.SetType (protocolNumber);
-      p.AddHeader (llc);
-      return SendTo(p, dest);
+      return SendTo(p, dest, protocolNumber);
     }
   else
     {
@@ -183,35 +225,38 @@
     }
 }
 
-TraceResolver *
-NetDevice::CreateTraceResolver (TraceContext const &context)
-{
-  return DoCreateTraceResolver (context);
-}
-
 Ptr<Channel>
 NetDevice::GetChannel (void) const
 {
+  NS_LOG_FUNCTION;
   return DoGetChannel ();
 }
 
-// Receive packet from below
+// Receive packets from below
 bool
-NetDevice::ForwardUp (Packet& packet)
+NetDevice::ForwardUp(const Packet& p, uint16_t param, const Address &from)
 {
+  NS_LOG_FUNCTION;
   bool retval = false;
-  LlcSnapHeader llc;
-  packet.RemoveHeader (llc);
+
+  NS_LOG_LOGIC ("UID is " << p.GetUid() << " device is: " << GetName());
+  
   if (!m_receiveCallback.IsNull ())
     {
-      retval = m_receiveCallback (this, packet, llc.GetType ());
+      retval = m_receiveCallback (this, p, param, from);
+    } 
+  else 
+    {
+      NS_LOG_WARN ("NetDevice::Receive call back is NULL");
     }
-  return retval;
+
+    return retval;
 }
 
 void 
 NetDevice::NotifyLinkUp (void)
 {
+  NS_LOG_FUNCTION;
   m_isUp = true;
   if (!m_linkChangeCallback.IsNull ())
     {
@@ -222,6 +267,7 @@
 void 
 NetDevice::NotifyLinkDown (void)
 {
+  NS_LOG_FUNCTION;
   m_isUp = false;
   if (!m_linkChangeCallback.IsNull ())
     {
@@ -232,24 +278,28 @@
 Ptr<Node>
 NetDevice::GetNode (void) const
 {
+  NS_LOG_FUNCTION;
   return m_node;
 }
 
 bool
 NetDevice::NeedsArp (void) const
 {
+  NS_LOG_FUNCTION;
   return DoNeedsArp ();
 }
 
 void 
-NetDevice::SetReceiveCallback (Callback<bool,Ptr<NetDevice>,const Packet &,uint16_t> cb)
+NetDevice::SetReceiveCallback (ReceiveCallback cb)
 {
+  NS_LOG_FUNCTION;
   m_receiveCallback = cb;
 }
 
 void
 NetDevice::DoDispose()
 {
+  NS_LOG_FUNCTION;
   m_node = 0;
 }
 
--- a/src/node/net-device.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/net-device.h	Fri Sep 28 11:59:46 2007 +0100
@@ -17,6 +17,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ * Modified by Emmanuelle Laprise to remove dependance on LLC headers
  */
 #ifndef NET_DEVICE_H
 #define NET_DEVICE_H
@@ -27,7 +28,8 @@
 #include "ns3/packet.h"
 #include "ns3/object.h"
 #include "ns3/ptr.h"
-#include "mac-address.h"
+#include "address.h"
+#include "ipv4-address.h"
 
 namespace ns3 {
 
@@ -61,14 +63,6 @@
   static const InterfaceId iid;
   virtual ~NetDevice();
 
-  /**
-   * \param context the trace context to use to construct the
-   *        TraceResolver to return
-   * \returns a TraceResolver which can resolve all traces
-   *          performed in this object. The caller must
-   *          delete the returned object.
-   */
-  TraceResolver *CreateTraceResolver (TraceContext const &context);
 
   /**
    * \return the channel this NetDevice is connected to. The value
@@ -78,9 +72,9 @@
   Ptr<Channel> GetChannel (void) const;
 
   /**
-   * \return the current MacAddress of this interface.
+   * \return the current Address of this interface.
    */
-  MacAddress GetAddress (void) const;
+  Address GetAddress (void) const;
   /**
    * \param mtu MTU value, in bytes, to set for the device
    * \return whether the MTU value was within legal bounds
@@ -136,11 +130,70 @@
    * Calling this method is invalid if IsBroadcast returns
    * not true.
    */
-  MacAddress const &GetBroadcast (void) const;
+  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
    */
@@ -153,11 +206,11 @@
    *        is received.
    * 
    *  Called from higher layer to send packet into Network Device
-   *  to the specified destination MacAddress
+   *  to the specified destination Address
    * 
    * \return whether the Send operation succeeded 
    */
-  bool Send(Packet& p, const MacAddress& dest, uint16_t protocolNumber);
+  bool Send(const Packet& p, const Address& dest, uint16_t protocolNumber);
   /**
    * \returns the node base class which contains this network
    *          interface.
@@ -177,30 +230,44 @@
   bool NeedsArp (void) const;
 
   /**
+   * \param device a pointer to the net device which is calling this callback
+   * \param packet the packet received
+   * \param protocol the 16 bit protocol number associated with this packet.
+   *        This protocol number is expected to be the same protocol number
+   *        given to the Send method by the user on the sender side.
+   * \param address the address of the sender
+   * \returns true if the callback could handle the packet successfully, false
+   *          otherwise.
+   */
+  typedef Callback<bool,Ptr<NetDevice>,const Packet &,uint16_t,const Address &> ReceiveCallback;
+
+  /**
    * \param cb callback to invoke whenever a packet has been received and must
    *        be forwarded to the higher layers.
+   *
    */
-  void SetReceiveCallback (Callback<bool,Ptr<NetDevice>,const Packet &,uint16_t> cb);
+  void SetReceiveCallback (ReceiveCallback cb);
 
  protected:
   /**
    * \param node base class node pointer of device's node 
    * \param addr MAC address of this device.
    */
-  NetDevice(Ptr<Node> node, const MacAddress& addr);
+  NetDevice(Ptr<Node> node, const Address& addr);
   /**
    * Enable broadcast support. This method should be
    * called by subclasses from their constructor
    */
-  void EnableBroadcast (MacAddress broadcast);
+  void EnableBroadcast (Address broadcast);
   /**
    * Set m_isBroadcast flag to false
    */
   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
    */
@@ -227,6 +294,9 @@
 
   /**
    * \param p packet sent from below up to Network Device
+   * \param param Extra parameter extracted from header and needed by
+   * some protocols
+   * \param address the address of the sender of this packet.
    * \returns true if the packet was forwarded successfully,
    *          false otherwise.
    *
@@ -234,7 +304,8 @@
    * forwards it to the higher layers by calling this method
    * which is responsible for passing it up to the Rx callback.
    */
-  bool ForwardUp (Packet& p);
+  bool ForwardUp (const Packet& p, uint16_t param, const Address &address);
+
 
   /**
    * The dispose method for this NetDevice class.
@@ -248,6 +319,7 @@
   /**
    * \param p packet to send
    * \param dest address of destination to which packet must be sent
+   * \param protocolNumber Number of the protocol (used with some protocols)
    * \returns true if the packet could be sent successfully, false
    *          otherwise.
    *
@@ -255,7 +327,7 @@
    * method.  When the link is Up, this method is invoked to ask 
    * subclasses to forward packets. Subclasses MUST override this method.
    */
-  virtual bool SendTo (Packet& p, const MacAddress& dest) = 0;
+  virtual bool SendTo (const Packet& p, const Address &dest, uint16_t protocolNumber) = 0;
   /**
    * \returns true if this NetDevice needs the higher-layers
    *          to perform ARP over it, false otherwise.
@@ -264,33 +336,25 @@
    */
   virtual bool DoNeedsArp (void) const = 0;
   /**
-   * \param context the trace context to associated to the
-   *        trace resolver.
-   * \returns a trace resolver associated to the input context.
-   *          the caller takes ownership of the pointer returned.
-   *
-   * Subclasses must implement this method.
-   */
-  virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context) = 0;
-  /**
    * \returns the channel associated to this NetDevice.
    *
    * Subclasses must implement this method.
    */
   virtual Ptr<Channel> DoGetChannel (void) const = 0;
 
-  Ptr<Node>         m_node;
+  Ptr<Node>     m_node;
   std::string   m_name;
   uint16_t      m_ifIndex;
-  MacAddress    m_address;
-  MacAddress    m_broadcast;
+  Address       m_address;
+  Address       m_broadcast;
+  Address       m_multicast;
   uint16_t      m_mtu;
   bool          m_isUp;
   bool          m_isBroadcast;
   bool          m_isMulticast;
   bool          m_isPointToPoint;
   Callback<void> m_linkChangeCallback;
-  Callback<bool,Ptr<NetDevice>,const Packet &,uint16_t> m_receiveCallback;
+  ReceiveCallback m_receiveCallback;
 };
 
 }; // namespace ns3
--- a/src/node/node-list.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/node-list.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -20,25 +20,42 @@
  *  Mathieu Lacage <mathieu.lacage@sophia.inria.fr>,
  */
 
-#include "ns3/array-trace-resolver.h"
-#include "ns3/trace-root.h"
+#include "ns3/composite-trace-resolver.h"
 #include "ns3/simulator.h"
 #include "ns3/simulation-singleton.h"
 #include "node-list.h"
 #include "node.h"
 
-namespace {
-static class Initialization 
+namespace ns3 {
+
+NodeListIndex::NodeListIndex ()
+  : m_index (0)
+{}
+NodeListIndex::NodeListIndex (uint32_t index)
+  : m_index (index)
+{}
+void 
+NodeListIndex::Print (std::ostream &os)
 {
-public:
-  Initialization ()
-  {
-    ns3::TraceRoot::Register ("nodes", ns3::MakeCallback (&ns3::NodeList::CreateTraceResolver));
-  }
-} g_initialization;
+  os << "nodeid=" << m_index;
+}
+uint16_t 
+NodeListIndex::GetUid (void)
+{
+  static uint16_t uid = AllocateUid<NodeListIndex> ("NodeListIndex");
+  return uid;
+}
+uint32_t 
+NodeListIndex::Get (void) const
+{
+  return m_index;
+}
+std::string 
+NodeListIndex::GetTypeName (void) const
+{
+  return "ns3::NodeListIndex";
 }
 
-namespace ns3 {
 
 /**
  * The private node list used by the static-based API
@@ -50,10 +67,9 @@
   ~NodeListPriv ();
 
   uint32_t Add (Ptr<Node> node);
-  NodeList::Iterator Begin (void);
-  NodeList::Iterator End (void);
-  TraceResolver *CreateTraceResolver (TraceContext const &context);
-  Node *PeekNode (uint32_t n);
+  NodeList::Iterator Begin (void) const;
+  NodeList::Iterator End (void) const;
+  Ptr<TraceResolver> GetTraceResolver (void) const;
   Ptr<Node> GetNode (uint32_t n);
   uint32_t GetNNodes (void);
 
@@ -85,12 +101,12 @@
   
 }
 NodeList::Iterator 
-NodeListPriv::Begin (void)
+NodeListPriv::Begin (void) const
 {
   return m_nodes.begin ();
 }
 NodeList::Iterator 
-NodeListPriv::End (void)
+NodeListPriv::End (void) const
 {
   return m_nodes.end ();
 }
@@ -99,11 +115,6 @@
 {
   return m_nodes.size ();
 }
-Node *
-NodeListPriv::PeekNode (uint32_t n)
-{
-  return PeekPointer (m_nodes[n]);
-}
 
 Ptr<Node>
 NodeListPriv::GetNode (uint32_t n)
@@ -112,14 +123,11 @@
 }
 
 
-TraceResolver *
-NodeListPriv::CreateTraceResolver (TraceContext const &context)
+Ptr<TraceResolver>
+NodeListPriv::GetTraceResolver (void) const
 {
-  ArrayTraceResolver<Node> *resolver =
-    new ArrayTraceResolver<Node>
-    (context, 
-     MakeCallback (&NodeListPriv::GetNNodes, this),
-     MakeCallback (&NodeListPriv::PeekNode, this));
+  Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
+  resolver->AddArray ("nodes", Begin (), End (), NodeListIndex ());
   return resolver;
 }
 
@@ -147,17 +155,30 @@
 {
   return SimulationSingleton<NodeListPriv>::Get ()->End ();
 }
-TraceResolver *
-NodeList::CreateTraceResolver (TraceContext const &context)
-{
-  return SimulationSingleton<NodeListPriv>::Get ()->CreateTraceResolver (context);
-}
 Ptr<Node>
 NodeList::GetNode (uint32_t n)
 {
   return SimulationSingleton<NodeListPriv>::Get ()->GetNode (n);
 }
 
-
-
+void 
+NodeList::Connect (std::string name, const CallbackBase &cb)
+{
+  SimulationSingleton<NodeListPriv>::Get ()->GetTraceResolver ()->Connect (name, cb, TraceContext ());
+}
+void 
+NodeList::Disconnect (std::string name, const CallbackBase &cb)
+{
+  SimulationSingleton<NodeListPriv>::Get ()->GetTraceResolver ()->Disconnect (name, cb);
+}
+void 
+NodeList::TraceAll (std::ostream &os)
+{
+  SimulationSingleton<NodeListPriv>::Get ()->GetTraceResolver ()->TraceAll (os, TraceContext ());
+}
+Ptr<TraceResolver> 
+NodeList::GetTraceResolver (void)
+{
+  return SimulationSingleton<NodeListPriv>::Get ()->GetTraceResolver ();
+}
 }//namespace ns3
--- a/src/node/node-list.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/node-list.h	Fri Sep 28 11:59:46 2007 +0100
@@ -23,14 +23,34 @@
 #define NODE_LIST_H
 
 #include <vector>
-#include "ns3/array-trace-resolver.h"
+#include "ns3/trace-context-element.h"
 #include "ns3/ptr.h"
 
 namespace ns3 {
 
 class Node;
+class CallbackBase;
 class TraceResolver;
-class TraceContext;
+
+/**
+ * \brief hold in a TraceContext the index of a node within a NodeList.
+ */
+class NodeListIndex : public TraceContextElement
+{
+public:
+  NodeListIndex ();
+  NodeListIndex (uint32_t index);
+  void Print (std::ostream &os);
+  static uint16_t GetUid (void);
+  /**
+   * \returns the index of the node within the NodeList
+   */
+  uint32_t Get (void) const;
+  std::string GetTypeName (void) const;
+private:
+  uint32_t m_index;
+};
+
 
 /**
  * \brief the list of simulation nodes.
@@ -40,8 +60,7 @@
 class NodeList
 {
 public:
-  typedef ArrayTraceResolver<Node>::Index NodeIndex;
-  typedef std::vector< Ptr<Node> >::iterator Iterator;
+  typedef std::vector< Ptr<Node> >::const_iterator Iterator;
 
   /**
    * \param node node to add
@@ -62,18 +81,49 @@
    */
   static Iterator End (void);
   /**
-   * \param context trace context to use for trace resolver
-   *        to create.
-   * \returns the requested trace resolver. The caller
-   *          takes ownership of the returned pointer.
-   */
-  static TraceResolver *CreateTraceResolver (TraceContext const &context);
-
-  /**
    * \param n index of requested node.
    * \returns the Node associated to index n.
    */
   static Ptr<Node> GetNode (uint32_t n);
+  /**
+   * \param name namespace regexp to match
+   * \param cb callback to connect
+   *
+   * Connect input callback to all trace sources which match
+   * the input namespace regexp.
+   * A tutorial which explains how to use this method can be
+   * found in the \ref tracing section.
+   */
+  static void Connect (std::string name, const CallbackBase &cb);
+  /**
+   * \param name namespace regexp to match
+   * \param cb callback to connect
+   *
+   * Disconnect input callback from all trace sources which match
+   * the input namespace regexp.
+   */
+  static void Disconnect (std::string name, const CallbackBase &cb);
+  /**
+   * \param os the output stream on which the content of each trace event should be
+   *        dumped in ascii format.
+   *
+   * Enable _every_ trace source accessible from the NodeList and write to the
+   * output stream an ascii representation of each trace event.
+   * This method is very useful to get quick-and-dirty trace output from a 
+   * simulation.
+   * More fancy tracing output could be generated with the ns3::NodeList::Connect
+   * method as explained in the \ref tracing section.
+   */
+  static void TraceAll (std::ostream &os);
+  /**
+   * \returns the trace resolver used by the ns3::NodeList::Connect,
+   * ns3::NodeList::Disconnect, and, ns3::NodeList::TraceAll methods.
+   *
+   * Using this method directly is not really recommended. Instead, users
+   * should use one of the three methods ns3::NodeList::Connect,
+   * ns3::NodeList::Disconnect, or, ns3::NodeList::TraceAll methods.
+   */
+  static Ptr<TraceResolver> GetTraceResolver (void);
 };
 
 }//namespace ns3
--- a/src/node/node.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/node.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -1,60 +1,98 @@
-// -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*-
-//
-// Copyright (c) 2006 Georgia Tech Research Corporation
-// 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
-// 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: George F. Riley<riley@ece.gatech.edu>
-//
-
-// Implement the basic Node object for ns3.
-// George F. Riley, Georgia Tech, Fall 2006
-
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 Georgia Tech Research Corporation, 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
+ *
+ * Authors: George F. Riley<riley@ece.gatech.edu>
+ *          Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
 #include "node.h"
 #include "node-list.h"
 #include "net-device.h"
 #include "application.h"
+#include "packet-socket-factory.h"
 #include "ns3/simulator.h"
+#include "ns3/composite-trace-resolver.h"
 
 namespace ns3{
 
 const InterfaceId Node::iid = MakeInterfaceId ("Node", Object::iid);
 
+NodeNetDeviceIndex::NodeNetDeviceIndex ()
+  : m_index (0)
+{}
+NodeNetDeviceIndex::NodeNetDeviceIndex (uint32_t index)
+  : m_index (index)
+{}
+uint32_t 
+NodeNetDeviceIndex::Get (void) const
+{
+  return m_index;
+}
+void 
+NodeNetDeviceIndex::Print (std::ostream &os) const
+{
+  os << "device=" << m_index;
+}
+uint16_t 
+NodeNetDeviceIndex::GetUid (void)
+{
+  static uint16_t uid = AllocateUid<NodeNetDeviceIndex> ("NodeNetDeviceIndex");
+  return uid;
+}
+std::string 
+NodeNetDeviceIndex::GetTypeName (void) const
+{
+  return "ns3::NodeNetDeviceIndex";
+}
+
+
+
 Node::Node()
   : m_id(0), 
     m_sid(0)
 {
-  SetInterfaceId (Node::iid);
-  m_id = NodeList::Add (this);
+  Construct ();
 }
 
 Node::Node(uint32_t sid)
   : m_id(0), 
     m_sid(sid)
 { 
+  Construct ();
+}
+
+void
+Node::Construct (void)
+{
   SetInterfaceId (Node::iid);
   m_id = NodeList::Add (this);
+  Ptr<PacketSocketFactory> socketFactory = Create<PacketSocketFactory> ();
+  AddInterface (socketFactory);
 }
   
 Node::~Node ()
 {}
 
-TraceResolver *
-Node::CreateTraceResolver (TraceContext const &context)
+Ptr<TraceResolver>
+Node::GetTraceResolver (void) const
 {
-  return DoCreateTraceResolver (context);
+  Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
+  resolver->AddArray ("devices", m_devices.begin (), m_devices.end (), NodeNetDeviceIndex ());
+  resolver->SetParentResolver (Object::GetTraceResolver ());
+  return resolver;
 }
 
 uint32_t 
@@ -74,8 +112,9 @@
 {
   uint32_t index = m_devices.size ();
   m_devices.push_back (device);
-  DoAddDevice (device);
   device->SetIfIndex(index);
+  device->SetReceiveCallback (MakeCallback (&Node::ReceiveFromDevice, this));
+  NotifyDeviceAdded (device);
   return index;
 }
 Ptr<NetDevice>
@@ -107,8 +146,8 @@
   return m_applications.size ();
 }
 
-
-void Node::DoDispose()
+void 
+Node::DoDispose()
 {
   for (std::vector<Ptr<NetDevice> >::iterator i = m_devices.begin ();
        i != m_devices.end (); i++)
@@ -129,4 +168,56 @@
   Object::DoDispose ();
 }
 
+void 
+Node::NotifyDeviceAdded (Ptr<NetDevice> device)
+{}
+
+void
+Node::RegisterProtocolHandler (ProtocolHandler handler, 
+                               uint16_t protocolType,
+                               Ptr<NetDevice> device)
+{
+  struct Node::ProtocolHandlerEntry entry;
+  entry.handler = handler;
+  entry.protocol = protocolType;
+  entry.device = device;
+  m_handlers.push_back (entry);
+}
+
+void
+Node::UnregisterProtocolHandler (ProtocolHandler handler)
+{
+  for (ProtocolHandlerList::iterator i = m_handlers.begin ();
+       i != m_handlers.end (); i++)
+    {
+      if (i->handler.IsEqual (handler))
+        {
+          m_handlers.erase (i);
+          break;
+        }
+    }
+}
+
+bool
+Node::ReceiveFromDevice (Ptr<NetDevice> device, const Packet &packet, 
+                         uint16_t protocol, const Address &from)
+{
+  bool found = false;
+  for (ProtocolHandlerList::iterator i = m_handlers.begin ();
+       i != m_handlers.end (); i++)
+    {
+      if (i->device == 0 ||
+          (i->device != 0 && i->device == device))
+        {
+          if (i->protocol == 0 || 
+              i->protocol == protocol)
+            {
+              i->handler (device, packet, protocol, from);
+              found = true;
+            }
+        }
+    }
+  return found;
+}
+
 }//namespace ns3
--- a/src/node/node.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/node.h	Fri Sep 28 11:59:46 2007 +0100
@@ -1,33 +1,31 @@
-// -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*-
-//
-// Copyright (c) 2006 Georgia Tech Research Corporation
-// 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
-// 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: George F. Riley<riley@ece.gatech.edu>
-//
-
-// Define the basic Node object for ns3.
-// George F. Riley, Georgia Tech, Fall 2006
-
-#ifndef I_NODE_H
-#define I_NODE_H
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 Georgia Tech Research Corporation, 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
+ *
+ * Authors: George F. Riley<riley@ece.gatech.edu>
+ *          Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef NODE_H
+#define NODE_H
 
 #include <vector>
 
 #include "ns3/object.h"
+#include "ns3/callback.h"
+#include "ns3/trace-context-element.h"
 
 namespace ns3 {
 
@@ -35,6 +33,28 @@
 class TraceResolver;
 class NetDevice;
 class Application;
+class Packet;
+class Address;
+class CompositeTraceResolver;
+
+/**
+ * \brief hold in a TraceContext the index of a NetDevice within a Node
+ */
+class NodeNetDeviceIndex : public TraceContextElement
+{
+public:
+  NodeNetDeviceIndex ();
+  NodeNetDeviceIndex (uint32_t index);
+  /**
+   * \returns the index of the NetDevice within its container Node.
+   */
+  uint32_t Get (void) const;
+  void Print (std::ostream &os) const;
+  std::string GetTypeName (void) const;
+  static uint16_t GetUid (void);
+private:
+  uint32_t m_index;
+};
 
 /**
  * \brief A network Node.
@@ -58,18 +78,18 @@
 public:
   static const InterfaceId iid;
 
-  virtual ~Node();
-
+  /**
+   * Must be invoked by subclasses only.
+   */
+  Node();
   /**
-   * \param context the trace context for the TraceResolver to create
-   * \returns a newly-created TraceResolver. The caller takes
-   *          ownership of the returned pointer.
+   * \param systemId a unique integer used for parallel simulations.
    *
-   * Request the Node to create a trace resolver. This method
-   * could be used directly by a user who needs access to very low-level
-   * trace configuration.
+   * Must be invoked by subclasses only.
    */
-  TraceResolver *CreateTraceResolver (TraceContext const &context);
+  Node(uint32_t systemId);
+
+  virtual ~Node();
 
   /**
    * \returns the unique id of this node.
@@ -93,11 +113,15 @@
    * Associate this device to this node.
    * This method is called automatically from NetDevice::NetDevice
    * so the user has little reason to call this method himself.
+   * The index returned is always non-zero.
    */
   uint32_t AddDevice (Ptr<NetDevice> device);
   /**
    * \param index the index of the requested NetDevice
    * \returns the requested NetDevice associated to this Node.
+   *
+   * The indexes used by the GetDevice method start at one and
+   * end at GetNDevices ()
    */
   Ptr<NetDevice> GetDevice (uint32_t index) const;
   /**
@@ -127,17 +151,35 @@
    */
   uint32_t GetNApplications (void) const;
 
-protected:
   /**
-   * Must be invoked by subclasses only.
+   * A protocol handler
    */
-  Node();
+  typedef Callback<void,Ptr<NetDevice>, const Packet &,uint16_t,const Address &> ProtocolHandler;
   /**
-   * \param systemId a unique integer used for parallel simulations.
+   * \param handler the handler to register
+   * \param protocolType the type of protocol this handler is 
+   *        interested in. This protocol type is a so-called
+   *        EtherType, as registered here:
+   *        http://standards.ieee.org/regauth/ethertype/eth.txt
+   *        the value zero is interpreted as matching all
+   *        protocols.
+   * \param device the device attached to this handler. If the
+   *        value is zero, the handler is attached to all
+   *        devices on this node.
+   */
+  void RegisterProtocolHandler (ProtocolHandler handler, 
+                                uint16_t protocolType,
+                                Ptr<NetDevice> device);
+  /**
+   * \param handler the handler to unregister
    *
-   * Must be invoked by subclasses only.
+   * After this call returns, the input handler will never
+   * be invoked anymore.
    */
-  Node(uint32_t systemId);
+  void UnregisterProtocolHandler (ProtocolHandler handler);
+
+protected:
+  virtual Ptr<TraceResolver> GetTraceResolver (void) const;
   /**
    * The dispose method. Subclasses must override this method
    * and must chain up to it by calling Node::DoDispose at the
@@ -145,13 +187,7 @@
    */
   virtual void DoDispose (void);
 private:
-  /**
-   * \param context the trace context
-   * \returns a trace resolver to the user. The user must delete it.
-   *
-   * Subclasses must implement this method.
-   */
-  virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context) = 0;
+
   /**
    * \param device the device added to this Node.
    *
@@ -160,14 +196,25 @@
    * at this point to setup the node's receive function for
    * the NetDevice packets.
    */
-  virtual void DoAddDevice (Ptr<NetDevice> device) const = 0;
+  virtual void NotifyDeviceAdded (Ptr<NetDevice> device);
+
+  bool ReceiveFromDevice (Ptr<NetDevice> device, const Packet &packet, 
+                          uint16_t protocol, const Address &from);
+  void Construct (void);
 
+  struct ProtocolHandlerEntry {
+    ProtocolHandler handler;
+    uint16_t protocol;
+    Ptr<NetDevice> device;
+  };
+  typedef std::vector<struct Node::ProtocolHandlerEntry> ProtocolHandlerList;
   uint32_t    m_id;         // Node id for this node
   uint32_t    m_sid;        // System id for this node
   std::vector<Ptr<NetDevice> > m_devices;
   std::vector<Ptr<Application> > m_applications;
+  ProtocolHandlerList m_handlers;
 };
 
 } //namespace ns3
 
-#endif /* I_NODE_H */
+#endif /* NODE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/packet-socket-address.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,134 @@
+/* -*-  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 "packet-socket-address.h"
+#include "net-device.h"
+
+namespace ns3 {
+
+PacketSocketAddress::PacketSocketAddress ()
+{}
+void 
+PacketSocketAddress::SetProtocol (uint16_t protocol)
+{
+  m_protocol = protocol;
+}
+void
+PacketSocketAddress::SetAllDevices (void)
+{
+  m_isSingleDevice = false;
+  m_device = 0;
+}
+void 
+PacketSocketAddress::SetSingleDevice (uint32_t index)
+{
+  m_isSingleDevice = true;
+  m_device = index;
+}
+void 
+PacketSocketAddress::SetPhysicalAddress (const Address address)
+{
+  m_address = address;
+}
+
+uint16_t 
+PacketSocketAddress::GetProtocol (void) const
+{
+  return m_protocol;
+}
+bool
+PacketSocketAddress::IsSingleDevice (void) const
+{
+  return m_isSingleDevice;
+}
+uint32_t
+PacketSocketAddress::GetSingleDevice (void) const
+{
+  return m_device;
+}
+Address 
+PacketSocketAddress::GetPhysicalAddress (void) const
+{
+  return m_address;
+}
+
+PacketSocketAddress::operator Address () const
+{
+  return ConvertTo ();
+}
+
+Address 
+PacketSocketAddress::ConvertTo (void) const
+{
+  Address address;
+  uint8_t buffer[Address::MAX_SIZE];
+  buffer[0] = m_protocol & 0xff;
+  buffer[1] = (m_protocol >> 8) & 0xff;
+  buffer[2] = (m_device >> 24) & 0xff;
+  buffer[3] = (m_device >> 16) & 0xff;
+  buffer[4] = (m_device >> 8) & 0xff;
+  buffer[5] = (m_device >> 0) & 0xff;
+  buffer[6] = m_isSingleDevice?1:0;
+  uint32_t copied = m_address.CopyAllTo (buffer + 7, Address::MAX_SIZE - 7);
+  return Address (GetType (), buffer, 7 + copied);
+}
+PacketSocketAddress 
+PacketSocketAddress::ConvertFrom (const Address &address)
+{
+  NS_ASSERT (IsMatchingType (address));
+  uint8_t buffer[Address::MAX_SIZE];
+  address.CopyTo (buffer);
+  uint16_t protocol = buffer[0] | (buffer[1] << 8);
+  uint32_t device = 0;
+  device |= buffer[2];
+  device <<= 8;
+  device |= buffer[3];
+  device <<= 8;
+  device |= buffer[4];
+  device <<= 8;
+  device |= buffer[5];
+  bool isSingleDevice = (buffer[6] == 1)?true:false;
+  Address physical;
+  physical.CopyAllFrom (buffer + 7, Address::MAX_SIZE - 7);
+  PacketSocketAddress ad;
+  ad.SetProtocol (protocol);
+  if (isSingleDevice)
+    {
+      ad.SetSingleDevice (device);
+    }
+  else
+    {
+      ad.SetAllDevices ();
+    }
+  ad.SetPhysicalAddress (physical);
+  return ad;
+}
+bool 
+PacketSocketAddress::IsMatchingType (const Address &address)
+{
+  return address.IsMatchingType (GetType ());
+}
+uint8_t 
+PacketSocketAddress::GetType (void)
+{
+  static uint8_t type = Address::Register ();
+  return type;
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/packet-socket-address.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,77 @@
+/* -*-  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 PACKET_SOCKET_ADDRESS_H
+#define PACKET_SOCKET_ADDRESS_H
+
+#include "ns3/ptr.h"
+#include "address.h"
+#include "mac48-address.h"
+#include "mac64-address.h"
+#include "net-device.h"
+
+namespace ns3 {
+
+class NetDevice;
+
+class PacketSocketAddress
+{
+ public:
+  PacketSocketAddress ();
+  void SetProtocol (uint16_t protocol);
+
+  void SetAllDevices (void);
+  void SetSingleDevice (uint32_t device);
+  void SetPhysicalAddress (const Address address);
+
+  uint16_t GetProtocol (void) const;
+  uint32_t GetSingleDevice (void) const;
+  bool IsSingleDevice (void) const;
+  Address GetPhysicalAddress (void) const;
+
+  /**
+   * \returns a new Address instance
+   *
+   * Convert an instance of this class to a polymorphic Address instance.
+   */
+  operator Address () const;
+  /**
+   * \param address a polymorphic address
+   *
+   * Convert a polymorphic address to an Mac48Address instance.
+   * The conversion performs a type check.
+   */
+  static PacketSocketAddress ConvertFrom (const Address &address);
+  /**
+   * \returns true if the address matches, false otherwise.
+   */
+  static bool IsMatchingType (const Address &address);
+ private:
+  static uint8_t GetType (void);
+  Address ConvertTo (void) const;
+  uint16_t m_protocol;
+  bool m_isSingleDevice;
+  uint32_t m_device;
+  Address m_address;
+};
+
+
+} // namespace ns3
+
+#endif /* PACKET_SOCKET_ADDRESS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/packet-socket-factory.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,41 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise
+ * 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
+ * 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+ */
+#include "packet-socket-factory.h"
+#include "node.h"
+#include "packet-socket.h"
+
+namespace ns3 {
+
+const InterfaceId PacketSocketFactory::iid = MakeInterfaceId ("Packet", 
+                                                              SocketFactory::iid);
+
+PacketSocketFactory::PacketSocketFactory ()
+{
+  SetInterfaceId (PacketSocketFactory::iid);
+}
+
+Ptr<Socket> PacketSocketFactory::CreateSocket (void)
+{
+  Ptr<Node> node = QueryInterface<Node> (Node::iid);
+  Ptr<PacketSocket> socket = Create<PacketSocket> (node);
+  return socket;
+} 
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/packet-socket-factory.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,51 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise
+ * 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
+ * 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+ */
+#ifndef PACKET_SOCKET_FACTORY_H
+#define PACKET_SOCKET_FACTORY_H
+
+#include "socket-factory.h"
+
+namespace ns3 {
+
+class Socket;
+
+/**
+ * This can be used as an interface in a node in order for the node to
+ * generate PacketSockets that can connect to net devices.
+ */
+class PacketSocketFactory : public SocketFactory
+{
+public:
+  static const InterfaceId iid; /// Interface identifier
+
+  PacketSocketFactory ();
+
+  /**
+   * Creates a PacketSocket and returns a pointer to it.
+   *
+   * \return a pointer to the created socket
+   */
+  virtual Ptr<Socket> CreateSocket (void);
+};
+
+} // namespace ns3
+
+#endif /* PACKET_SOCKET_FACTORY_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/packet-socket.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,304 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise, 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
+ *
+ * Authors: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+ *          Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+
+#include "packet-socket.h"
+#include "packet-socket-address.h"
+#include "ns3/log.h"
+#include "ns3/node.h"
+
+NS_LOG_COMPONENT_DEFINE ("PacketSocket");
+
+namespace ns3 {
+
+PacketSocket::PacketSocket (Ptr<Node> node)
+  : m_node (node)
+{
+  NS_LOG_FUNCTION;
+  Init();
+}
+
+void 
+PacketSocket::Init()
+{
+  NS_LOG_FUNCTION;
+  m_state = STATE_OPEN;
+  m_shutdownSend = false;
+  m_shutdownRecv = false;
+  m_errno = ERROR_NOTERROR;
+}
+
+PacketSocket::~PacketSocket ()
+{
+  NS_LOG_FUNCTION;
+}
+
+void 
+PacketSocket::DoDispose (void)
+{
+  NS_LOG_FUNCTION;
+  m_device = 0;
+}
+
+enum Socket::SocketErrno
+PacketSocket::GetErrno (void) const
+{
+  NS_LOG_FUNCTION;
+  return m_errno;
+}
+
+Ptr<Node>
+PacketSocket::GetNode (void) const
+{
+  NS_LOG_FUNCTION;
+  return m_node;
+}
+
+int
+PacketSocket::Bind (void)
+{
+  NS_LOG_FUNCTION;
+  PacketSocketAddress address;
+  address.SetProtocol (0);
+  address.SetAllDevices ();
+  return DoBind (address);
+}
+
+int
+PacketSocket::Bind (const Address &address)
+{ 
+  NS_LOG_FUNCTION;
+  if (!PacketSocketAddress::IsMatchingType (address))
+    {
+      m_errno = ERROR_INVAL;
+      return -1;
+    }
+  PacketSocketAddress ad = PacketSocketAddress::ConvertFrom (address);
+  return DoBind (ad);
+}
+
+int
+PacketSocket::DoBind (const PacketSocketAddress &address)
+{
+  NS_LOG_FUNCTION;
+  if (m_state == STATE_BOUND ||
+      m_state == STATE_CONNECTED)
+    {
+      m_errno = ERROR_INVAL;
+      return -1;
+    }
+  if (m_state == STATE_CLOSED)
+    {
+      m_errno = ERROR_BADF;
+      return -1;
+    }
+  Ptr<NetDevice> dev ;
+  if (address.IsSingleDevice ())
+    {
+      dev = 0;
+    }
+  else
+    {
+      m_node->GetDevice (address.GetSingleDevice ());
+    }
+  m_node->RegisterProtocolHandler (MakeCallback (&PacketSocket::ForwardUp, this),
+                                   address.GetProtocol (), dev);
+  m_state = STATE_BOUND;
+  m_protocol = address.GetProtocol ();
+  m_isSingleDevice = address.IsSingleDevice ();
+  m_device = address.GetSingleDevice ();
+  return 0;
+}
+
+int
+PacketSocket::ShutdownSend (void)
+{
+  NS_LOG_FUNCTION;
+  if (m_state == STATE_CLOSED)
+    {
+      m_errno = ERROR_BADF;
+      return -1;
+    }
+  m_shutdownSend = true;
+  return 0;
+}
+
+int
+PacketSocket::ShutdownRecv (void)
+{
+  NS_LOG_FUNCTION;
+  if (m_state == STATE_CLOSED)
+    {
+      m_errno = ERROR_BADF;
+      return -1;
+    }
+  m_shutdownRecv = false;
+  return 0;
+}
+
+int
+PacketSocket::Close(void)
+{
+  NS_LOG_FUNCTION;
+  if (m_state == STATE_CLOSED)
+    {
+      m_errno = ERROR_BADF;
+      return -1;
+    }
+  m_state = STATE_CLOSED;
+  NotifyCloseCompleted ();
+  return 0;
+}
+
+int
+PacketSocket::Connect(const Address &ad)
+{
+  NS_LOG_FUNCTION;
+  PacketSocketAddress address;
+  if (m_state == STATE_CLOSED)
+    {
+      m_errno = ERROR_BADF;
+      goto error;
+    }
+  if (m_state == STATE_OPEN)
+    {
+      // connect should happen _after_ bind.
+      m_errno = ERROR_INVAL; // generic error condition.
+      goto error;
+    }
+  if (m_state == STATE_CONNECTED)
+    {
+      m_errno = ERROR_ISCONN;
+      goto error;
+    }
+  if (!PacketSocketAddress::IsMatchingType (ad))
+    {
+      m_errno = ERROR_AFNOSUPPORT;
+      goto error;
+    }
+  m_destAddr = ad;
+  m_state = STATE_CONNECTED;
+  NotifyConnectionSucceeded ();
+  return 0;
+ error:
+  NotifyConnectionFailed ();
+  return -1;
+}
+
+int
+PacketSocket::Send (const Packet &p)
+{
+  NS_LOG_FUNCTION;
+  if (m_state == STATE_OPEN ||
+      m_state == STATE_BOUND)
+    {
+      m_errno = ERROR_NOTCONN;
+      return -1;
+    }
+  return SendTo (m_destAddr, p);
+}
+
+int
+PacketSocket::SendTo(const Address &address, const Packet &p)
+{
+  NS_LOG_FUNCTION;
+  PacketSocketAddress ad;
+  if (m_state == STATE_CLOSED)
+    {
+      m_errno = ERROR_BADF;
+      return -1;
+    }
+  if (m_state == STATE_OPEN)
+    {
+      // XXX should return another error here.
+      m_errno = ERROR_INVAL;
+      return -1;
+    }
+  if (m_shutdownSend)
+    {
+      m_errno = ERROR_SHUTDOWN;
+      return -1;
+    }
+  if (!PacketSocketAddress::IsMatchingType (address))
+    {
+      m_errno = ERROR_AFNOSUPPORT;
+      return -1;
+    }
+  ad = PacketSocketAddress::ConvertFrom (address);
+  
+  bool error = false;
+  Address dest = ad.GetPhysicalAddress ();
+  if (ad.IsSingleDevice ())
+    {
+      Ptr<NetDevice> device = m_node->GetDevice (ad.GetSingleDevice ());
+      if (!device->Send (p, dest, ad.GetProtocol ()))
+        {
+          error = true;
+        }
+    }
+  else
+    {
+      for (uint32_t i = 0; i < m_node->GetNDevices (); i++)
+        {
+          Ptr<NetDevice> device = m_node->GetDevice (i);
+          if (!device->Send (p, dest, ad.GetProtocol ()))
+            {
+              error = true;
+            }
+        }
+    }
+  if (!error)
+    {
+      NotifyDataSent (p.GetSize ());
+    }
+
+  if (error)
+    {
+      m_errno = ERROR_INVAL;
+      return -1;
+    }
+  else
+    {
+      return 0;
+    }
+}
+
+void 
+PacketSocket::ForwardUp (Ptr<NetDevice> device, const Packet &packet, 
+                         uint16_t protocol, const Address &from)
+{
+  NS_LOG_FUNCTION;
+  if (m_shutdownRecv)
+    {
+      return;
+    }
+
+  Packet p = packet;
+
+  PacketSocketAddress address;
+  address.SetPhysicalAddress (from);
+  address.SetSingleDevice (device->GetIfIndex ());
+  address.SetProtocol (protocol);
+
+  NS_LOG_LOGIC ("UID is " << packet.GetUid() << " PacketSocket " << this);
+  NotifyDataReceived (p, address);
+}
+
+}//namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/packet-socket.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,119 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise, 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
+ *
+ * Authors: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>,
+ *          Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef PACKET_SOCKET_H
+#define PACKET_SOCKET_H
+
+#include <stdint.h>
+#include "ns3/callback.h"
+#include "ns3/ptr.h"
+#include "ns3/socket.h"
+
+namespace ns3 {
+
+class Node;
+class Packet;
+class NetDevice;
+class PacketSocketAddress;
+
+/**
+ * \brief A PacketSocket is a link between an application and a net device.
+ *
+ * A PacketSocket can be used to connect an application to a net
+ * device. The application provides the buffers of data, the socket
+ * conserts them to a raw packet and the net device then adds the
+ * protocol specific headers and trailers. This socket type
+ * is very similar to the linux and BSD "packet" sockets.
+ *
+ * Here is a summary of the semantics of this class:
+ * - Bind: Bind uses only the protocol and device fields of the 
+ *       PacketSocketAddress. If none are provided, Bind uses 
+ *       zero for both, which means that the socket is bound
+ *       to all protocols on all devices on the node.
+ *
+ * - Connect: uses only the protocol, device and "physical address" 
+ *       field of the PacketSocketAddress. It is used to set the default
+ *       destination address for outgoing packets.
+ *
+ * - Send: send the input packet to the underlying NetDevices
+ *       with the default destination address. The socket must
+ *       be bound and connected.
+ *
+ * - SendTo: uses the protocol, device, and "physical address" 
+ *       fields of the PacketSocketAddress. The device value is 
+ *       used to specialize the packet transmission to a single 
+ *       device, the protocol value specifies the protocol of this
+ *       packet only and the "physical address" field is used to override the 
+ *       default destination address. The socket must be bound.
+ *
+ * - Recv: The address represents the address of the packer originator.
+ *       The fields "physical address", device, and protocol are filled.
+ *
+ * - Accept: not allowed
+ */
+class PacketSocket : public Socket
+{
+public:
+  PacketSocket (Ptr<Node> node);
+  virtual ~PacketSocket ();
+
+  virtual enum SocketErrno GetErrno (void) const;
+  virtual Ptr<Node> GetNode (void) const;
+  virtual int Bind (void);
+  virtual int Bind (const Address & address);
+  virtual int Close (void);
+  virtual int ShutdownSend (void);
+  virtual int ShutdownRecv (void);
+  virtual int Connect(const Address &address);
+  virtual int Send (const Packet &p);
+  virtual int SendTo(const Address &address,const Packet &p);
+
+
+private:
+
+private:
+  void Init (void);
+  void ForwardUp (Ptr<NetDevice> device, const Packet &packet, 
+                  uint16_t protocol, const Address &from);
+  int DoBind (const PacketSocketAddress &address);
+  virtual void DoDispose (void);
+
+  enum State {
+    STATE_OPEN,
+    STATE_BOUND,     // open and bound
+    STATE_CONNECTED, // open, bound and connected
+    STATE_CLOSED
+  };
+  Ptr<Node> m_node;
+  enum SocketErrno m_errno;
+  bool m_shutdownSend;
+  bool m_shutdownRecv;
+  enum State m_state;
+  uint16_t m_protocol;
+  bool m_isSingleDevice;
+  uint32_t m_device;
+  Address m_destAddr; /// Default destination address
+};
+
+}//namespace ns3
+
+#endif /* PACKET_SOCKET_H */
+
+
--- a/src/node/queue.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/queue.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -17,13 +17,13 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#include "ns3/debug.h"
+#include "ns3/log.h"
 #include "ns3/composite-trace-resolver.h"
 #include "ns3/default-value.h"
 #include "ns3/component-manager.h"
 #include "queue.h"
 
-NS_DEBUG_COMPONENT_DEFINE ("Queue");
+NS_LOG_COMPONENT_DEFINE ("Queue");
 
 namespace ns3 {
 
@@ -31,6 +31,72 @@
 static ClassIdDefaultValue g_classIdDefaultValue ("Queue", "Packet Queue",
                                                   Queue::iid, "DropTailQueue");
 
+
+std::string 
+QueueTraceType::GetTypeName (void) const
+{
+  NS_LOG_FUNCTION;
+  return "ns3::QueueTraceType";
+}
+
+uint16_t 
+QueueTraceType::GetUid (void)
+{
+  NS_LOG_FUNCTION;
+  static uint16_t uid = AllocateUid<QueueTraceType> ("QueueTraceType");
+  return uid;
+}
+
+QueueTraceType::QueueTraceType ()
+  : m_type (QueueTraceType::ENQUEUE)
+{
+  NS_LOG_FUNCTION;
+}
+
+QueueTraceType::QueueTraceType (enum Type type)
+  : m_type (type)
+{
+  NS_LOG_FUNCTION;
+}
+
+bool 
+QueueTraceType::IsEnqueue (void) const
+{
+  NS_LOG_FUNCTION;
+  return m_type == ENQUEUE;
+}
+
+bool 
+QueueTraceType::IsDequeue (void) const
+{
+  NS_LOG_FUNCTION;
+  return m_type == DEQUEUE;
+}
+
+bool 
+QueueTraceType::IsDrop (void) const
+{
+  NS_LOG_FUNCTION;
+  return m_type == DROP;
+}
+
+void 
+QueueTraceType::Print (std::ostream &os) const
+{
+  os << "queue-";
+  switch (m_type) {
+  case QueueTraceType::ENQUEUE:
+    os << "enqueue";
+    break;
+  case QueueTraceType::DEQUEUE:
+    os << "dequeue";
+    break;
+  case QueueTraceType::DROP:
+    os << "drop";
+    break;
+  }
+}
+
 Queue::Queue() : 
   m_nBytes(0), 
   m_nTotalReceivedBytes(0),
@@ -39,31 +105,42 @@
   m_nTotalDroppedBytes(0),
   m_nTotalDroppedPackets(0)
 {
+  NS_LOG_FUNCTION;
   SetInterfaceId (Queue::iid);
-  NS_DEBUG("Queue::Queue ()");
 }
 
 Queue::~Queue()
 {
-  NS_DEBUG("Queue::~Queue ()");
+  NS_LOG_FUNCTION;
 }
 
-TraceResolver *
-Queue::CreateTraceResolver (TraceContext const &context)
+Ptr<TraceResolver>
+Queue::GetTraceResolver (void) const
 {
-  CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
-  resolver->Add ("enqueue", m_traceEnqueue, Queue::ENQUEUE);
-  resolver->Add ("dequeue", m_traceDequeue, Queue::DEQUEUE);
-  resolver->Add ("drop", m_traceDrop, Queue::DROP);
+  NS_LOG_FUNCTION;
+  Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
+  resolver->AddSource ("enqueue", 
+                       TraceDoc ("store packet in queue",
+                                 "const Packet &", "packet queued"),
+                       m_traceEnqueue, QueueTraceType (QueueTraceType::ENQUEUE));
+  resolver->AddSource ("dequeue", 
+                       TraceDoc ("remove packet from queue",
+                                 "const Packet &", "packet dequeued"),
+                       m_traceDequeue, QueueTraceType (QueueTraceType::DEQUEUE));
+  resolver->AddSource ("drop", 
+                       TraceDoc ("drop packet from queue", 
+                                 "const Packet &", "packet dropped"),
+                       m_traceDrop, QueueTraceType (QueueTraceType::DROP));
+  resolver->SetParentResolver (Object::GetTraceResolver ());
   return resolver;
 }
 
 bool 
 Queue::Enqueue (const Packet& p)
 {
-  NS_DEBUG("Queue::Enqueue (" << &p << ")");
-
-  NS_DEBUG("Queue::Enqueue (): m_traceEnqueue (p)");
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << &p << ")");
+  NS_LOG_LOGIC ("m_traceEnqueue (p)");
 
   m_traceEnqueue (p);
 
@@ -79,7 +156,8 @@
 bool
 Queue::Dequeue (Packet &p)
 {
-  NS_DEBUG("Queue::Dequeue (" << &p << ")");
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << &p << ")");
 
   bool retval = DoDequeue (p);
 
@@ -91,7 +169,7 @@
       NS_ASSERT (m_nBytes >= 0);
       NS_ASSERT (m_nPackets >= 0);
 
-      NS_DEBUG("Queue::Dequeue (): m_traceDequeue (p)");
+      NS_LOG_LOGIC("m_traceDequeue (p)");
 
       const Packet packet = p;
       m_traceDequeue (packet);
@@ -103,16 +181,15 @@
 void
 Queue::DequeueAll (void)
 {
-  NS_DEBUG("Queue::DequeueAll ()");
-
-  NS_ASSERT (!"Don't know what to do with dequeued packets!");
+  NS_LOG_FUNCTION;
+  NS_ASSERT_MSG (0, "Don't know what to do with dequeued packets!");
 }
 
 bool
 Queue::Peek (Packet &p)
 {
-  NS_DEBUG("Queue::Peek (" << &p << ")");
-
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << &p << ")");
   return DoPeek (p);
 }
 
@@ -120,66 +197,63 @@
 uint32_t 
 Queue::GetNPackets (void)
 {
-  NS_DEBUG("Queue::GetNPackets () <= " << m_nPackets);
-
+  NS_LOG_FUNCTION;
+  NS_LOG_LOGIC ("returns " << m_nPackets);
   return m_nPackets;
 }
 
 uint32_t
 Queue::GetNBytes (void)
 {
-  NS_DEBUG("Queue::GetNBytes () <= " << m_nBytes);
-
+  NS_LOG_FUNCTION;
+  NS_LOG_LOGIC (" returns " << m_nBytes);
   return m_nBytes;
 }
 
-
 bool
 Queue::IsEmpty (void)
 {
-  NS_DEBUG("Queue::IsEmpty () <= " << (m_nPackets == 0));
+  NS_LOG_FUNCTION;
+  NS_LOG_LOGIC ("returns " << (m_nPackets == 0));
   return m_nPackets == 0;
 }
 
 uint32_t
 Queue::GetTotalReceivedBytes (void)
 {
-  NS_DEBUG("Queue::GetTotalReceivedBytes () <= " << m_nTotalReceivedBytes);
-
+  NS_LOG_FUNCTION;
+  NS_LOG_LOGIC("returns " << m_nTotalReceivedBytes);
   return m_nTotalReceivedBytes;
 }
 
 uint32_t
 Queue::GetTotalReceivedPackets (void)
 {
-  NS_DEBUG("Queue::GetTotalReceivedPackets () <= " << m_nTotalReceivedPackets);
-
+  NS_LOG_FUNCTION;
+  NS_LOG_LOGIC ("returns " << m_nTotalReceivedPackets);
   return m_nTotalReceivedPackets;
 }
 
 uint32_t
 Queue:: GetTotalDroppedBytes (void)
 {
-  NS_DEBUG(
-    "Queue::GetTotalDroppedBytes () <= " << m_nTotalDroppedBytes
-    );
+  NS_LOG_FUNCTION;
+  NS_LOG_LOGIC ("returns " << m_nTotalDroppedBytes);
   return m_nTotalDroppedBytes;
 }
 
 uint32_t
 Queue::GetTotalDroppedPackets (void)
 {
-  NS_DEBUG(
-           "Queue::GetTotalDroppedPackets () <= " << m_nTotalDroppedPackets);
-
+  NS_LOG_FUNCTION;
+  NS_LOG_LOGIC("returns " << m_nTotalDroppedPackets);
   return m_nTotalDroppedPackets;
 }
 
 void 
 Queue::ResetStatistics (void)
 {
-  NS_DEBUG("Queue::ResetStatistics ()");
-
+  NS_LOG_FUNCTION;
   m_nTotalReceivedBytes = 0;
   m_nTotalReceivedPackets = 0;
   m_nTotalDroppedBytes = 0;
@@ -189,18 +263,20 @@
 void
 Queue::Drop (const Packet& p)
 {
-  NS_DEBUG("Queue::Drop (" << &p << ")");
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << &p << ")");
 
   m_nTotalDroppedPackets++;
   m_nTotalDroppedBytes += p.GetSize ();
 
-  NS_DEBUG("Queue::Drop (): m_traceDrop (p)");
+  NS_LOG_LOGIC ("m_traceDrop (p)");
   m_traceDrop (p);
 }
 
 Ptr<Queue>
 Queue::CreateDefault (void)
 {
+  NS_LOG_FUNCTION;
   ClassId classId = g_classIdDefaultValue.GetValue ();
   Ptr<Queue> queue = ComponentManager::Create<Queue> (classId, Queue::iid);
   return queue;
--- a/src/node/queue.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/queue.h	Fri Sep 28 11:59:46 2007 +0100
@@ -31,12 +31,46 @@
 #include "ns3/object.h"
 #include "ns3/callback-trace-source.h"
 #include "ns3/trace-resolver.h"
+#include "ns3/trace-context-element.h"
 
 namespace ns3 {
 
 class StringEnumDefaultValue;
 
 /**
+ * \brief hold in a TraceContext the type of a trace source 
+ */
+class QueueTraceType : public TraceContextElement
+{
+public:
+  enum Type {
+    ENQUEUE,
+    DEQUEUE,
+    DROP
+  };
+  static uint16_t GetUid (void);
+  QueueTraceType ();
+  QueueTraceType (enum Type type);
+  /**
+   * \returns true if this is an enqueue event, false otherwise.
+   */
+  bool IsEnqueue (void) const;
+  /**
+   * \returns true if this is a dequeue event, false otherwise.
+   */
+  bool IsDequeue (void) const;
+  /**
+   * \returns true if this is a drop event, false otherwise.
+   */
+  bool IsDrop (void) const;
+  void Print (std::ostream &os) const;
+  std::string GetTypeName (void) const;
+private:
+  enum Type m_type;
+};
+
+
+/**
  * \brief Abstract base class for packet Queues
  * 
  * This class defines the base APIs for packet queues in the ns-3 system
@@ -46,15 +80,8 @@
 public:
   static const InterfaceId iid;
 
-  enum TraceType {
-    ENQUEUE,
-    DEQUEUE,
-    DROP,
-  };
   Queue ();
   virtual ~Queue ();
-
-  TraceResolver *CreateTraceResolver (TraceContext const &context);
   
   /**
    * \return true if the queue is empty; false otherwise
@@ -151,6 +178,7 @@
   virtual bool DoPeek (Packet &p) = 0;
 
 protected:
+  Ptr<TraceResolver> GetTraceResolver (void) const;
   // called by subclasses to notify parent of packet drops.
   void Drop (const Packet& p);
 
--- a/src/node/socket.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/socket.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -1,81 +1,176 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 Georgia Tech Research Corporation
+ *               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
+ *
+ * Authors: George F. Riley<riley@ece.gatech.edu>
+ *          Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+
+#include "ns3/log.h"
+#include "ns3/packet.h"
 #include "socket.h"
 
+NS_LOG_COMPONENT_DEFINE ("Socket");
+
 namespace ns3 {
 
 Socket::~Socket ()
-{}
+{
+  NS_LOG_FUNCTION;
+}
+
+void 
+Socket::SetCloseCallback (Callback<void,Ptr<Socket> > closeCompleted)
+{
+  NS_LOG_FUNCTION;
+  m_closeCompleted = closeCompleted;
+}
+
+void 
+Socket::SetConnectCallback (
+  Callback<void, Ptr<Socket> > connectionSucceeded,
+  Callback<void, Ptr<Socket> > connectionFailed,
+  Callback<void, Ptr<Socket> > halfClose)
+{
+  NS_LOG_FUNCTION;
+  m_connectionSucceeded = connectionSucceeded;
+  m_connectionFailed = connectionFailed;
+  m_halfClose = halfClose;
+}
 
 void 
-Socket::Close(Callback<void, Ptr<Socket> > closeCompleted)
+Socket::SetAcceptCallback (
+  Callback<bool, Ptr<Socket>, const Address &> connectionRequest,
+  Callback<void, Ptr<Socket>, const Address&> newConnectionCreated,
+  Callback<void, Ptr<Socket> > closeRequested)
+{
+  NS_LOG_FUNCTION;
+  m_connectionRequest = connectionRequest;
+  m_newConnectionCreated = newConnectionCreated;
+  m_closeRequested = closeRequested;
+}
+
+void 
+Socket::SetSendCallback (Callback<void, Ptr<Socket>, uint32_t> dataSent)
+{
+  NS_LOG_FUNCTION;
+  m_dataSent = dataSent;
+}
+
+void 
+Socket::SetRecvCallback (Callback<void, Ptr<Socket>, const Packet &,const Address&> receivedData)
 {
-  DoClose (closeCompleted);
+  NS_LOG_FUNCTION;
+  m_receivedData = receivedData;
+}
+
+void 
+Socket::NotifyCloseCompleted (void)
+{
+  NS_LOG_FUNCTION;
+  if (!m_closeCompleted.IsNull ())
+    {
+      m_closeCompleted (this);
+    }
+}
+
+void 
+Socket::NotifyConnectionSucceeded (void)
+{
+  NS_LOG_FUNCTION;
+  if (!m_connectionSucceeded.IsNull ())
+    {
+      m_connectionSucceeded (this);
+    }
 }
 
 void 
-Socket::Connect(const Ipv4Address & address,
-               uint16_t portNumber,
-               Callback<void, Ptr<Socket> > connectionSucceeded,
-               Callback<void, Ptr<Socket> > connectionFailed,
-               Callback<void, Ptr<Socket> > halfClose)
+Socket::NotifyConnectionFailed (void)
 {
-  DoConnect (address, portNumber, connectionSucceeded, connectionFailed, halfClose);
+  NS_LOG_FUNCTION;
+  if (!m_connectionFailed.IsNull ())
+    {
+      m_connectionFailed (this);
+    }
 }
-int
-Socket::Accept(Callback<bool, Ptr<Socket>, const Ipv4Address&, uint16_t> connectionRequest,
-	       Callback<void, Ptr<Socket>, const Ipv4Address&, uint16_t> newConnectionCreated,
-	       Callback<void, Ptr<Socket> > closeRequested)
-{
-  return DoAccept (connectionRequest, newConnectionCreated, closeRequested);
-}
-int 
-Socket::Send (const uint8_t* buffer,
-	      uint32_t size,
-	      Callback<void, Ptr<Socket>, uint32_t> dataSent)
+
+void 
+Socket::NotifyHalfClose (void)
 {
-  return DoSend (buffer, size, dataSent);
+  NS_LOG_FUNCTION;
+  if (!m_halfClose.IsNull ())
+    {
+      m_halfClose (this);
+    }
 }
-int 
-Socket::SendTo(const Ipv4Address &address,
-	       uint16_t port,
-	       const uint8_t *buffer,
-	       uint32_t size,
-	       Callback<void, Ptr<Socket>, uint32_t> dataSent)
+
+bool 
+Socket::NotifyConnectionRequest (const Address &from)
 {
-  return DoSendTo (address, port, buffer, size, dataSent);
-}
-void 
-Socket::Recv(Callback<void, Ptr<Socket>, const uint8_t*, uint32_t,const Ipv4Address&, uint16_t> callback)
-{
-  DoRecv (callback);
-}
-void 
-Socket::RecvDummy(Callback<void, Ptr<Socket>, uint32_t,const Ipv4Address&, uint16_t> callback)
-{
-  DoRecvDummy (callback);
+  NS_LOG_FUNCTION;
+  if (!m_connectionRequest.IsNull ())
+    {
+      return m_connectionRequest (this, from);
+    }
+  else
+    {
+      // refuse all incomming connections by default.
+      return false;
+    }
 }
 
+void 
+Socket::NotifyNewConnectionCreated (Ptr<Socket> socket, const Address &from)
+{
+  NS_LOG_FUNCTION;
+  if (!m_newConnectionCreated.IsNull ())
+    {
+      m_newConnectionCreated (socket, from);
+    }
+}
 
-bool 
-Socket::RefuseAllConnections (Ptr<Socket> socket, const Ipv4Address& address, uint16_t port)
-{
-  return false;
-}
 void 
-Socket::DummyCallbackVoidSocket (Ptr<Socket> socket)
-{}
-void
-Socket::DummyCallbackVoidSocketUi32 (Ptr<Socket> socket, uint32_t)
-{}
+Socket::NotifyCloseRequested (void)
+{
+  NS_LOG_FUNCTION;
+  if (!m_closeRequested.IsNull ())
+    {
+      m_closeRequested (this);
+    }
+}
+
 void 
-Socket::DummyCallbackVoidSocketUi32Ipv4AddressUi16 (Ptr<Socket> socket, uint32_t, const Ipv4Address &, uint16_t)
-{}
+Socket::NotifyDataSent (uint32_t size)
+{
+  NS_LOG_FUNCTION;
+  if (!m_dataSent.IsNull ())
+    {
+      m_dataSent (this, size);
+    }
+}
+
 void 
-Socket::DummyCallbackVoidSocketBufferUi32Ipv4AddressUi16 (Ptr<Socket> socket, const uint8_t *, uint32_t,
-							  const Ipv4Address &, uint16_t)
-{}
-void 
-Socket::DummyCallbackVoidSocketIpv4AddressUi16 (Ptr<Socket> socket, const Ipv4Address &, uint16_t)
-{}
-
+Socket::NotifyDataReceived (const Packet &p, const Address &from)
+{
+  NS_LOG_FUNCTION;
+  if (!m_receivedData.IsNull ())
+    {
+      m_receivedData (this, p, from);
+    }
+}
 
 }//namespace ns3
--- a/src/node/socket.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/socket.h	Fri Sep 28 11:59:46 2007 +0100
@@ -1,42 +1,44 @@
-/* -*-  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
-//
-// Author: George F. Riley<riley@ece.gatech.edu>
-//
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 Georgia Tech Research Corporation
+ *               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
+ *
+ * Authors: George F. Riley<riley@ece.gatech.edu>
+ *          Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
 
 #ifndef __SOCKET_H__
 #define __SOCKET_H__
 
 #include "ns3/callback.h"
 #include "ns3/ptr.h"
-#include "ipv4-address.h"
 #include "ns3/object.h"
+#include "address.h"
 #include <stdint.h>
 
 namespace ns3 {
 
 class Node;
+class Packet;
 
 /**
  * \brief Define a Socket API based on the BSD Socket API.
  *
  * Contrary to the original BSD socket API, this API is asynchronous:
- * it does not contain blocking calls. This API also does not use
- * the dreaded BSD sockaddr_t type. Other than that, it tries to stick
+ * it does not contain blocking calls. Other than that, it tries to stick
  * to the BSD API to make it easier those who know the BSD API to use
  * this API.
  */
@@ -53,6 +55,10 @@
     ERROR_AGAIN,
     ERROR_SHUTDOWN,
     ERROR_OPNOTSUPP,
+    ERROR_AFNOSUPPORT,
+    ERROR_INVAL,
+    ERROR_BADF,
+    ERROR_NOROUTETOHOST,
     SOCKET_ERRNO_LAST
   };
 
@@ -68,53 +74,77 @@
    */
   virtual Ptr<Node> GetNode (void) const = 0;
 
+  /**
+   * \param closeCompleted Callback invoked when the close operation is
+   *        completed.
+   */
+  void SetCloseCallback (Callback<void,Ptr<Socket> > closeCompleted);
+
+  /**
+   * \param connectionSucceeded this callback is invoked when the connection request
+   *        initiated by the user is successfully completed. The callback is passed
+   *        back a pointer to the same socket object.
+   * \param connectionFailed this callback is invoked when the connection request
+   *        initiated by the user is unsuccessfully completed. The callback is passed
+   *        back a pointer to the same socket object. 
+   * \param halfClose XXX When exactly is this callback invoked ? If it invoked when the
+   *        other side closes the connection ? Or when I call Close ?
+   */
+  void SetConnectCallback (Callback<void, Ptr<Socket> > connectionSucceeded,
+                          Callback<void, Ptr<Socket> > connectionFailed,
+                          Callback<void, Ptr<Socket> > halfClose);
+  /**
+   * \brief Accept connection requests from remote hosts
+   * \param connectionRequest Callback for connection request from peer. 
+   *        This user callback is passed a pointer to this socket, the 
+   *        ip address and the port number of the connection originator. 
+   *        This callback must return true to accept the incoming connection,
+   *        false otherwise. If the connection is accepted, the 
+   *        "newConnectionCreated" callback will be invoked later to give access
+   *        to the user to the socket created to match this new connection. If the
+   *        user does not explicitely specify this callback, all incoming 
+   *        connections will be refused.
+   * \param newConnectionCreated Callback for new connection: when a new
+   *        is accepted, it is created and the corresponding socket is passed
+   *        back to the user through this callback. This user callback is passed
+   *        a pointer to the new socket, and the ip address and port number
+   *        of the connection originator.
+   * \param closeRequested Callback for connection close request from peer.
+   *        XXX: when is this callback invoked ?
+   */
+  void SetAcceptCallback (Callback<bool, Ptr<Socket>, const Address &> connectionRequest,
+                                 Callback<void, Ptr<Socket>, const Address&> newConnectionCreated,
+                                 Callback<void, Ptr<Socket> > closeRequested);
+  void SetSendCallback (Callback<void, Ptr<Socket>, uint32_t> dataSent);
+  /**
+   * \brief Receive data
+   * \param receivedData Invoked whenever new data is received.
+   *
+   */
+  void SetRecvCallback (Callback<void, Ptr<Socket>, const Packet &,const Address&> receivedData);
+
   /** 
-   * Allocate a free port number and
-   * bind this socket to this port number on all
-   * interfaces of this system.
+   * \param address the address to try to allocate
+   * \returns 0 on success, -1 on failure.
+   *
+   * Allocate a local endpoint for this socket.
+   */
+  virtual int Bind (const Address &address) = 0;
+
+  /** 
+   * Allocate a local endpoint for this socket.
    *
    * \returns 0 on success, -1 on failure.
    */
-  virtual int Bind (void) = 0;
-
-  /** 
-   * Allocate a free port number and
-   * bind this socket to this port number on the
-   * specified interface.
-   *
-   * \param address address of interface to bind to.
-   * \returns 0 on success, -1 on failure.
-   */
-  virtual int Bind (Ipv4Address address) = 0;
-
-  /**
-   * Bind this socket to this port number
-   * on all interfaces of this system.
-   *
-   * \param port port to bind to on all interfaces
-   * \returns 0 on success, -1 on failure.
-   */
-  virtual int Bind (uint16_t port) = 0; 
-
-  /**
-   * Bind this socket to this port number
-   * on the interface specified by address.
-   *
-   * \param address address of interface to bind to.
-   * \param port port to bind to on specified interface
-   * \returns 0 on success, -1 on failure.
-   */
-  virtual int Bind (Ipv4Address address, uint16_t port) = 0;
+  virtual int Bind () = 0;
 
   /** 
    * \brief Close a socket.
-   * \param closeCompleted Callback invoked when the close operation is
-   *        completed.
    *
    * After the Close call, the socket is no longer valid, and cannot
    * safely be used for subsequent operations.
    */
-  void Close(Callback<void, Ptr<Socket> > closeCompleted = MakeCallback (&Socket::DummyCallbackVoidSocket));
+  virtual int Close(void) = 0;
 
   /**
    * \returns zero on success, -1 on failure.
@@ -134,127 +164,47 @@
 
   /**
    * \brief Initiate a connection to a remote host
-   * \param address IP Address of remote.
-   * \param portNumber Port number of remote
-   * \param connectionSucceeded this callback is invoked when the connection request
-   *        initiated by the user is successfully completed. The callback is passed
-   *        back a pointer to the same socket object.
-   * \param connectionFailed this callback is invoked when the connection request
-   *        initiated by the user is unsuccessfully completed. The callback is passed
-   *        back a pointer to the same socket object. 
-   * \param halfClose XXX When exactly is this callback invoked ? If it invoked when the
-   *        other side closes the connection ? Or when I call Close ?
+   * \param address Address of remote.
    */
-  void Connect(const Ipv4Address & address,
-               uint16_t portNumber,
-               Callback<void, Ptr<Socket> > connectionSucceeded = MakeCallback(&Socket::DummyCallbackVoidSocket),
-               Callback<void, Ptr<Socket> > connectionFailed = MakeCallback(&Socket::DummyCallbackVoidSocket),
-               Callback<void, Ptr<Socket> > halfClose = MakeCallback(&Socket::DummyCallbackVoidSocket));
+  virtual int Connect(const Address &address) = 0;
     
   /**
-   * \brief Accept connection requests from remote hosts
-   * \param connectionRequest Callback for connection request from peer. 
-   *        This user callback is passed a pointer to this socket, the 
-   *        ip address and the port number of the connection originator. 
-   *        This callback must return true to accept the incoming connection,
-   *        false otherwise. If the connection is accepted, the 
-   *        "newConnectionCreated" callback will be invoked later to give access
-   *        to the user to the socket created to match this new connection. If the
-   *        user does not explicitely specify this callback, all incoming 
-   *        connections will be refused.
-   * \param newConnectionCreated Callback for new connection: when a new
-   *        is accepted, it is created and the corresponding socket is passed
-   *        back to the user through this callback. This user callback is passed
-   *        a pointer to the new socket, and the ip address and port number
-   *        of the connection originator.
-   * \param closeRequested Callback for connection close request from peer.
-   *        XXX: when is this callback invoked ?
-   */
-  int Accept(Callback<bool, Ptr<Socket>, const Ipv4Address&, uint16_t> connectionRequest = 
-             MakeCallback(&Socket::RefuseAllConnections),
-             Callback<void, Ptr<Socket>, const Ipv4Address&, uint16_t> newConnectionCreated = 
-             MakeCallback (&Socket::DummyCallbackVoidSocketIpv4AddressUi16),
-             Callback<void, Ptr<Socket> > closeRequested = MakeCallback (&Socket::DummyCallbackVoidSocket));
-
-  /**
    * \brief Send data (or dummy data) to the remote host
-   * \param buffer Data to send (nil if dummy data).
-   * \param size Number of bytes to send.
-   * \param dataSent Data sent callback.
+   * \param p packet to send
    * \returns -1 in case of error or the number of bytes copied in the 
    *          internal buffer and accepted for transmission.
    */
-  int Send (const uint8_t* buffer,
-            uint32_t size,
-            Callback<void, Ptr<Socket>, uint32_t> dataSent = MakeCallback (&Socket::DummyCallbackVoidSocketUi32));
+  virtual int Send (const Packet &p) = 0;
   
   /**
    * \brief Send data to a specified peer.
    * \param address IP Address of remote host
-   * \param port port number
-   * \param buffer Data to send (nil if dummy data).
-   * \param size Number of bytes to send.
-   * \param dataSent Data sent callback.
+   * \param p packet to send
    * \returns -1 in case of error or the number of bytes copied in the 
    *          internal buffer and accepted for transmission.
    */
-  int SendTo(const Ipv4Address &address,
-             uint16_t port,
-             const uint8_t *buffer,
-             uint32_t size,
-             Callback<void, Ptr<Socket>, uint32_t> dataSent = MakeCallback (&Socket::DummyCallbackVoidSocketUi32));
-  
-  /**
-   * \brief Receive data
-   * \param receivedData Invoked whenever new data is received.
-   *
-   * If you wish to transport only dummy packets, this method is not a very
-   * efficient way to receive these dummy packets: it will trigger a memory
-   * allocation to hold the dummy memory into a buffer which can be passed
-   * to the user. Instead, consider using the RecvDummy method.
-   */
-  void Recv(Callback<void, Ptr<Socket>, const uint8_t*, uint32_t,const Ipv4Address&, uint16_t> receivedData = 
-            MakeCallback (&Socket::DummyCallbackVoidSocketBufferUi32Ipv4AddressUi16));
-  
-  /**
-   * \brief Receive data
-   * \param receivedData Invoked whenever new data is received.
-   *
-   * This method is included because it is vastly more efficient than the 
-   * Recv method when you use dummy payload.
-   */
-  void RecvDummy(Callback<void, Ptr<Socket>, uint32_t,const Ipv4Address&, uint16_t> receivedData =
-                 MakeCallback (&Socket::DummyCallbackVoidSocketUi32Ipv4AddressUi16));
+  virtual int SendTo(const Address &address,const Packet &p) = 0;
 
-private:
-  virtual void DoClose(Callback<void, Ptr<Socket> > closeCompleted) = 0;
-  virtual void DoConnect(const Ipv4Address & address,
-                         uint16_t portNumber,
-                         Callback<void, Ptr<Socket> > connectionSucceeded,
-                         Callback<void, Ptr<Socket> > connectionFailed,
-                         Callback<void, Ptr<Socket> > halfClose) = 0;
-  virtual int DoAccept(Callback<bool, Ptr<Socket>, const Ipv4Address&, uint16_t> connectionRequest,
-                       Callback<void, Ptr<Socket>, const Ipv4Address&, uint16_t> newConnectionCreated,
-                       Callback<void, Ptr<Socket> > closeRequested) = 0;
-  virtual int DoSend (const uint8_t* buffer,
-                    uint32_t size,
-                    Callback<void, Ptr<Socket>, uint32_t> dataSent) = 0;
-  virtual int DoSendTo(const Ipv4Address &address,
-                       uint16_t port,
-                       const uint8_t *buffer,
-                       uint32_t size,
-                       Callback<void, Ptr<Socket>, uint32_t> dataSent) = 0;
-  virtual void DoRecv(Callback<void, Ptr<Socket>, const uint8_t*, uint32_t,const Ipv4Address&, uint16_t> receive) = 0;
-  virtual void DoRecvDummy(Callback<void, Ptr<Socket>, uint32_t,const Ipv4Address&, uint16_t>) = 0;
+protected:
+  void NotifyCloseCompleted (void);
+  void NotifyConnectionSucceeded (void);
+  void NotifyConnectionFailed (void);
+  void NotifyHalfClose (void);
+  bool NotifyConnectionRequest (const Address &from);
+  void NotifyNewConnectionCreated (Ptr<Socket> socket, const Address &from);
+  void NotifyCloseRequested (void);
+  void NotifyDataSent (uint32_t size);
+  void NotifyDataReceived (const Packet &p, const Address &from);
 
-
-  static bool RefuseAllConnections (Ptr<Socket> socket, const Ipv4Address& address, uint16_t port);
-  static void DummyCallbackVoidSocket (Ptr<Socket> socket);
-  static void DummyCallbackVoidSocketUi32 (Ptr<Socket> socket, uint32_t);
-  static void DummyCallbackVoidSocketUi32Ipv4AddressUi16 (Ptr<Socket> socket, uint32_t, const Ipv4Address &, uint16_t);
-  static void DummyCallbackVoidSocketBufferUi32Ipv4AddressUi16 (Ptr<Socket> socket, const uint8_t *, uint32_t, 
-                                                                const Ipv4Address &, uint16_t);
-  static void DummyCallbackVoidSocketIpv4AddressUi16 (Ptr<Socket> socket, const Ipv4Address &, uint16_t);
+  Callback<void,Ptr<Socket> >    m_closeCompleted;
+  Callback<void, Ptr<Socket> >   m_connectionSucceeded;
+  Callback<void, Ptr<Socket> >   m_connectionFailed;
+  Callback<void, Ptr<Socket> >   m_halfClose;
+  Callback<void, Ptr<Socket> >   m_closeRequested;
+  Callback<bool, Ptr<Socket>, const Address &>   m_connectionRequest;
+  Callback<void, Ptr<Socket>, const Address&>    m_newConnectionCreated;
+  Callback<void, Ptr<Socket>, uint32_t>          m_dataSent;
+  Callback<void, Ptr<Socket>, const Packet &,const Address&> m_receivedData;
 };
 
 } //namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/waf	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,1 @@
+exec "`dirname "$0"`"/../../waf "$@"
\ No newline at end of file
--- a/src/node/wscript	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/node/wscript	Fri Sep 28 11:59:46 2007 +0100
@@ -1,20 +1,20 @@
 ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
 
-def configure(conf):
-    conf.env.append_value('NS3_MODULES', 'ns3-node')
-
-
 def build(bld):
-    node = bld.create_obj('cpp', 'shlib')
-    node.name = 'ns3-node'
-    node.target = node.name
-    node.uselib_local = ['ns3-core', 'ns3-common', 'ns3-simulator']
+    node = bld.create_ns3_module('node', ['core', 'common', 'simulator'])
     node.source = [
+        'address.cc',
+        'mac48-address.cc',
+        'mac64-address.cc',
+        'inet-socket-address.cc',
+        'packet-socket-address.cc',
         'node.cc',
         'ipv4-address.cc',
         'net-device.cc',
-        'mac-address.cc',
+	'address-utils.cc',
         'llc-snap-header.cc',
+        'ethernet-header.cc',
+        'ethernet-trailer.cc',
         'ipv4-route.cc',
         'queue.cc',
         'drop-tail-queue.cc',
@@ -22,6 +22,8 @@
         'node-list.cc',
         'socket.cc',
         'socket-factory.cc',
+        'packet-socket-factory.cc',
+        'packet-socket.cc',
         'udp.cc',
         'ipv4.cc',
         'application.cc',
@@ -29,18 +31,26 @@
 
     headers = bld.create_obj('ns3header')
     headers.source = [
+        'address.h',
+        'mac48-address.h',
+        'mac64-address.h',
+        'inet-socket-address.h',
+        'packet-socket-address.h',
         'node.h',
         'ipv4-address.h',
         'net-device.h',
-        'mac-address.h',
+	'address-utils.h',
         'ipv4-route.h',
         'queue.h',
         'drop-tail-queue.h',
         'llc-snap-header.h',
+        'ethernet-header.h',
+        'ethernet-trailer.h',
         'channel.h',
         'node-list.h',
         'socket.h',
         'socket-factory.h',
+        'packet-socket-factory.h',
         'udp.h',
         'ipv4.h',
         'application.h',
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/routing/global-routing/candidate-queue.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,146 @@
+/* -*- 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
+ */
+
+#include "ns3/log.h"
+#include "ns3/assert.h"
+#include "candidate-queue.h"
+
+NS_LOG_COMPONENT_DEFINE ("CandidateQueue");
+
+namespace ns3 {
+
+CandidateQueue::CandidateQueue()
+  : m_candidates ()
+{
+  NS_LOG_FUNCTION;
+}
+
+CandidateQueue::~CandidateQueue()
+{
+  NS_LOG_FUNCTION;
+  Clear ();
+}
+
+  void
+CandidateQueue::Clear (void)
+{
+  NS_LOG_FUNCTION;
+  while (!m_candidates.empty ())
+    {
+      SPFVertex *p = Pop ();
+      delete p;
+      p = 0;
+    }
+}
+
+  void
+CandidateQueue::Push (SPFVertex *vNew)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << vNew << ")");
+
+  CandidateList_t::iterator i = m_candidates.begin ();  
+
+  for (; i != m_candidates.end (); i++)
+    {
+      SPFVertex *v = *i;
+      if (vNew->GetDistanceFromRoot () < v->GetDistanceFromRoot ())
+        {
+          break;
+        }
+    }
+  m_candidates.insert(i, vNew);
+}
+
+  SPFVertex *
+CandidateQueue::Pop (void)
+{
+  NS_LOG_FUNCTION;
+  if (m_candidates.empty ())
+    {
+      return 0;
+    }
+
+  SPFVertex *v = m_candidates.front ();
+  m_candidates.pop_front ();
+  return v;
+}
+
+  SPFVertex *
+CandidateQueue::Top (void) const
+{
+  NS_LOG_FUNCTION;
+  if (m_candidates.empty ())
+    {
+      return 0;
+    }
+
+  return m_candidates.front ();
+}
+
+  bool
+CandidateQueue::Empty (void) const
+{
+  NS_LOG_FUNCTION;
+  return m_candidates.empty ();
+}
+
+  uint32_t
+CandidateQueue::Size (void) const
+{
+  NS_LOG_FUNCTION;
+  return m_candidates.size ();
+}
+
+  SPFVertex *
+CandidateQueue::Find (const Ipv4Address addr) const
+{
+  NS_LOG_FUNCTION;
+  CandidateList_t::const_iterator i = m_candidates.begin ();
+
+  for (; i != m_candidates.end (); i++)
+    {
+      SPFVertex *v = *i;
+      if (v->GetVertexId() == addr)
+        {
+          return v;
+        }
+    }
+
+  return 0;
+}
+
+  void
+CandidateQueue::Reorder (void)
+{
+  NS_LOG_FUNCTION;
+  std::list<SPFVertex*> temp;
+
+  while (!m_candidates.empty ()) {
+    SPFVertex *v = m_candidates.front ();
+    m_candidates.pop_front ();
+    temp.push_back(v);
+  }
+
+  while (!temp.empty ()) {
+    Push (temp.front ());
+    temp.pop_front ();
+  }
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/routing/global-routing/candidate-queue.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,185 @@
+/* -*- 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:  Craig Dowell (craigdo@ee.washington.edu)
+ */
+
+#ifndef CANDIDATE_QUEUE_H
+#define CANDIDATE_QUEUE_H
+
+#include <stdint.h>
+#include <list>
+#include "global-route-manager-impl.h"
+
+namespace ns3 {
+
+/**  
+ * \brief A Candidate Queue used in static routing.
+ *
+ * The CandidateQueue is used in the OSPF shortest path computations.  It
+ * is a priority queue used to store candidates for the shortest path to a
+ * given network.  
+ *
+ * The queue holds Shortest Path First Vertex pointers and orders them
+ * according to the lowest value of the field m_distanceFromRoot.  Remaining
+ * vertices are ordered according to increasing distance.  This implements a
+ * priority queue.
+ *
+ * Although a STL priority_queue almost does what we want, the requirement
+ * for a Find () operation, the dynamic nature of the data and the derived
+ * requirement for a Reorder () operation led us to implement this simple 
+ * enhanced priority queue.
+ */
+class CandidateQueue
+{
+public:
+/**
+ * @brief Create an empty SPF Candidate Queue.  
+ * @internal
+ *
+ * @see SPFVertex
+ */
+  CandidateQueue ();
+
+/**
+ * @internal Destroy an SPF Candidate Queue and release any resources held 
+ * by the contents.
+ * @internal
+ *
+ * @see SPFVertex
+ */
+  virtual ~CandidateQueue ();
+
+/**
+ * @brief Empty the Candidate Queue and release all of the resources 
+ * associated with the Shortest Path First Vertex pointers in the queue.
+ * @internal
+ *
+ * @see SPFVertex
+ */
+  void Clear (void);
+
+/**
+ * @brief Push a Shortest Path First Vertex pointer onto the queue according
+ * to the priority scheme.
+ * @internal
+ * 
+ * On completion, the top of the queue will hold the Shortest Path First
+ * Vertex pointer that points to a vertex having lowest value of the field
+ * m_distanceFromRoot.  Remaining vertices are ordered according to 
+ * increasing distance.
+ *
+ * @see SPFVertex
+ * @param vNew The Shortest Path First Vertex to add to the queue.
+ */
+  void Push (SPFVertex *vNew);
+
+/**
+ * @brief Pop the Shortest Path First Vertex pointer at the top of the queue.
+ * @internal
+ *
+ * The caller is given the responsiblity for releasing the resources 
+ * associated with the vertex.
+ *
+ * @see SPFVertex
+ * @see Top ()
+ * @returns The Shortest Path First Vertex pointer at the top of the queue.
+ */
+  SPFVertex* Pop (void);
+
+/**
+ * @brief Return the Shortest Path First Vertex pointer at the top of the 
+ * queue.  
+ * @internal
+ *
+ * This method does not pop the SPFVertex* off of the queue, it simply 
+ * returns the pointer.
+ *
+ * @see SPFVertex
+ * @see Pop ()
+ * @returns The Shortest Path First Vertex pointer at the top of the queue.
+ */
+  SPFVertex* Top (void) const;
+
+/**
+ * @brief Test the Candidate Queue to determine if it is empty.
+ * @internal
+ *
+ * @returns True if the queue is empty, false otherwise.
+ */
+  bool Empty (void) const;
+
+/**
+ * @brief Return the number of Shortest Path First Vertex pointers presently
+ * stored in the Candidate Queue.
+ * @internal
+ *
+ * @see SPFVertex
+ * @returns The number of SPFVertex* pointers in the Candidate Queue.
+ */
+  uint32_t Size (void) const;
+
+/**
+ * @brief Searches the Candidate Queue for a Shortest Path First Vertex 
+ * pointer that points to a vertex having the given IP address.
+ * @internal
+ *
+ * @see SPFVertex
+ * @param addr The IP address to search for.
+ * @returns The SPFVertex* pointer corresponding to the given IP address.
+ */
+  SPFVertex* Find (const Ipv4Address addr) const;
+
+/**
+ * @brief Reorders the Candidate Queue according to the priority scheme.  
+ * @internal
+ * 
+ * On completion, the top of the queue will hold the Shortest Path First
+ * Vertex pointer that points to a vertex having lowest value of the field
+ * m_distanceFromRoot.  Remaining vertices are ordered according to 
+ * increasing distance.
+ *
+ * This method is provided in case the values of m_distanceFromRoot change
+ * during the routing calculations.
+ *
+ * @see SPFVertex
+ */
+  void Reorder (void);
+
+protected:
+  typedef std::list<SPFVertex*> CandidateList_t;
+  CandidateList_t m_candidates;
+
+private:
+/**
+ * Candidate Queue copy construction is disallowed (not implemented) to 
+ * prevent the compiler from slipping in incorrect versions that don't
+ * properly deal with deep copies.
+ */
+  CandidateQueue (CandidateQueue& sr);
+
+/**
+ * Candidate Queue assignment operator is disallowed (not implemented) to
+ * prevent the compiler from slipping in incorrect versions that don't
+ * properly deal with deep copies.
+ */
+  CandidateQueue& operator= (CandidateQueue& sr);
+};
+
+} // namespace ns3
+
+#endif /* CANDIDATE_QUEUE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/routing/global-routing/global-route-manager-impl.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,1625 @@
+/* -*- 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;
+ *
+ * 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
+ *
+ * Authors:  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>
+#include <vector>
+#include <queue>
+#include "ns3/assert.h"
+#include "ns3/fatal-error.h"
+#include "ns3/log.h"
+#include "ns3/node-list.h"
+#include "ns3/ipv4.h"
+#include "global-router-interface.h"
+#include "global-route-manager-impl.h"
+#include "candidate-queue.h"
+
+NS_LOG_COMPONENT_DEFINE ("GlobalRouteManager");
+
+namespace ns3 {
+
+// ---------------------------------------------------------------------------
+//
+// SPFVertex Implementation
+//
+// ---------------------------------------------------------------------------
+
+SPFVertex::SPFVertex () : 
+  m_vertexType (VertexUnknown), 
+  m_vertexId ("255.255.255.255"), 
+  m_lsa (0),
+  m_distanceFromRoot (SPF_INFINITY), 
+  m_rootOif (SPF_INFINITY),
+  m_nextHop ("0.0.0.0"),
+  m_parent (0),
+  m_children ()
+{
+  NS_LOG_FUNCTION;
+}
+
+SPFVertex::SPFVertex (GlobalRoutingLSA* lsa) : 
+  m_vertexId (lsa->GetLinkStateId ()),
+  m_lsa (lsa),
+  m_distanceFromRoot (SPF_INFINITY), 
+  m_rootOif (SPF_INFINITY),
+  m_nextHop ("0.0.0.0"),
+  m_parent (0),
+  m_children ()
+{
+  NS_LOG_FUNCTION;
+  if (lsa->GetLSType () == GlobalRoutingLSA::RouterLSA) 
+    {
+      NS_LOG_LOGIC ("Setting m_vertexType to VertexRouter");
+      m_vertexType = SPFVertex::VertexRouter;
+    }
+  else if (lsa->GetLSType () == GlobalRoutingLSA::NetworkLSA) 
+    { 
+      NS_LOG_LOGIC ("Setting m_vertexType to VertexNetwork");
+      m_vertexType = SPFVertex::VertexNetwork;
+    }
+}
+
+SPFVertex::~SPFVertex ()
+{
+  NS_LOG_FUNCTION;
+  for ( ListOfSPFVertex_t::iterator i = m_children.begin ();
+        i != m_children.end ();
+        i++)
+    {
+      SPFVertex *p = *i;
+      delete p;
+      p = 0;
+      *i = 0;
+    }
+  m_children.clear ();
+}
+
+  void 
+SPFVertex::SetVertexType (SPFVertex::VertexType type)
+{
+  NS_LOG_FUNCTION;
+  m_vertexType = type;
+}
+
+  SPFVertex::VertexType 
+SPFVertex::GetVertexType (void) const
+{
+  NS_LOG_FUNCTION;
+  return m_vertexType;
+}
+
+  void 
+SPFVertex::SetVertexId (Ipv4Address id)
+{
+  NS_LOG_FUNCTION;
+  m_vertexId = id;
+}
+
+  Ipv4Address
+SPFVertex::GetVertexId (void) const
+{
+  NS_LOG_FUNCTION;
+  return m_vertexId;
+}
+
+  void 
+SPFVertex::SetLSA (GlobalRoutingLSA* lsa)
+{
+  NS_LOG_FUNCTION;
+  m_lsa = lsa;
+}
+
+  GlobalRoutingLSA* 
+SPFVertex::GetLSA (void) const
+{
+  NS_LOG_FUNCTION;
+  return m_lsa;
+}
+
+  void 
+SPFVertex::SetDistanceFromRoot (uint32_t distance)
+{
+  NS_LOG_FUNCTION;
+  m_distanceFromRoot = distance;
+}
+
+  uint32_t
+SPFVertex::GetDistanceFromRoot (void) const
+{
+  NS_LOG_FUNCTION;
+  return m_distanceFromRoot;
+}
+
+  void 
+SPFVertex::SetOutgoingInterfaceId (uint32_t id)
+{
+  NS_LOG_FUNCTION;
+  m_rootOif = id;
+}
+
+  uint32_t 
+SPFVertex::GetOutgoingInterfaceId (void) const
+{
+  NS_LOG_FUNCTION;
+  return m_rootOif;
+}
+
+  void 
+SPFVertex::SetNextHop (Ipv4Address nextHop)
+{
+  NS_LOG_FUNCTION;
+  m_nextHop = nextHop;
+}
+
+  Ipv4Address
+SPFVertex::GetNextHop (void) const
+{
+  NS_LOG_FUNCTION;
+  return m_nextHop;
+}
+
+  void
+SPFVertex::SetParent (SPFVertex* parent)
+{
+  NS_LOG_FUNCTION;
+  m_parent = parent;
+}
+
+  SPFVertex* 
+SPFVertex::GetParent (void) const
+{
+  NS_LOG_FUNCTION;
+  return m_parent;
+}
+
+  uint32_t 
+SPFVertex::GetNChildren (void) const
+{
+  NS_LOG_FUNCTION;
+  return m_children.size ();
+}
+
+  SPFVertex* 
+SPFVertex::GetChild (uint32_t n) const
+{
+  NS_LOG_FUNCTION;
+  uint32_t j = 0;
+
+  for ( ListOfSPFVertex_t::const_iterator i = m_children.begin ();
+        i != m_children.end ();
+        i++, j++)
+    {
+      if (j == n)
+        {
+          return *i;
+        }
+    }
+  NS_ASSERT_MSG(false, "Index <n> out of range.");
+  return 0;
+}
+
+  uint32_t 
+SPFVertex::AddChild (SPFVertex* child)
+{
+  NS_LOG_FUNCTION;
+  m_children.push_back (child);
+  return m_children.size ();
+}
+
+// ---------------------------------------------------------------------------
+//
+// GlobalRouteManagerLSDB Implementation
+//
+// ---------------------------------------------------------------------------
+
+GlobalRouteManagerLSDB::GlobalRouteManagerLSDB ()
+:
+  m_database ()
+{
+  NS_LOG_FUNCTION;
+}
+
+GlobalRouteManagerLSDB::~GlobalRouteManagerLSDB ()
+{
+  NS_LOG_FUNCTION;
+  LSDBMap_t::iterator i;
+  for (i= m_database.begin (); i!= m_database.end (); i++)
+    {
+      NS_LOG_LOGIC ("free LSA");
+      GlobalRoutingLSA* temp = i->second;
+      delete temp;
+    }
+  NS_LOG_LOGIC ("clear map");
+  m_database.clear ();
+}
+
+  void
+GlobalRouteManagerLSDB::Initialize ()
+{
+  NS_LOG_FUNCTION;
+  LSDBMap_t::iterator i;
+  for (i= m_database.begin (); i!= m_database.end (); i++)
+    {
+      GlobalRoutingLSA* temp = i->second;
+      temp->SetStatus (GlobalRoutingLSA::LSA_SPF_NOT_EXPLORED);
+    }
+}
+
+  void
+GlobalRouteManagerLSDB::Insert (Ipv4Address addr, GlobalRoutingLSA* lsa)
+{
+  NS_LOG_FUNCTION;
+  m_database.insert (LSDBPair_t (addr, lsa));
+}
+
+  GlobalRoutingLSA*
+GlobalRouteManagerLSDB::GetLSA (Ipv4Address addr) const
+{
+  NS_LOG_FUNCTION;
+//
+// Look up an LSA by its address.
+//
+  LSDBMap_t::const_iterator i;
+  for (i= m_database.begin (); i!= m_database.end (); i++)
+  {
+    if (i->first == addr)
+    {
+      return i->second;
+    }
+  }
+  return 0;
+}
+
+  GlobalRoutingLSA*
+GlobalRouteManagerLSDB::GetLSAByLinkData (Ipv4Address addr) const
+{
+  NS_LOG_FUNCTION;
+//
+// Look up an LSA by its address.
+//
+  LSDBMap_t::const_iterator i;
+  for (i= m_database.begin (); i!= m_database.end (); i++)
+    {
+      GlobalRoutingLSA* temp = i->second;
+// Iterate among temp's Link Records
+      for (uint32_t j = 0; j < temp->GetNLinkRecords (); j++)
+        {
+          GlobalRoutingLinkRecord *lr = temp->GetLinkRecord (j);
+          if ( lr->GetLinkType () == GlobalRoutingLinkRecord::TransitNetwork &&
+               lr->GetLinkData () == addr)
+            {
+              return temp;
+            }
+        }
+    }
+  return 0;
+}
+
+// ---------------------------------------------------------------------------
+//
+// GlobalRouteManagerImpl Implementation
+//
+// ---------------------------------------------------------------------------
+
+GlobalRouteManagerImpl::GlobalRouteManagerImpl () 
+: 
+  m_spfroot (0) 
+{
+  NS_LOG_FUNCTION;
+  m_lsdb = new GlobalRouteManagerLSDB ();
+}
+
+GlobalRouteManagerImpl::~GlobalRouteManagerImpl ()
+{
+  NS_LOG_FUNCTION;
+  if (m_lsdb)
+    {
+      delete m_lsdb;
+    }
+}
+
+  void
+GlobalRouteManagerImpl::DebugUseLsdb (GlobalRouteManagerLSDB* lsdb)
+{
+  NS_LOG_FUNCTION;
+  if (m_lsdb)
+    {
+      delete m_lsdb;
+    }
+  m_lsdb = lsdb;
+}
+
+//
+// In order to build the routing database, we need at least one of the nodes
+// to participate as a router.  Eventually we expect to provide a mechanism
+// for selecting a subset of the nodes to participate; for now, we just make
+// all nodes routers.  We do this by walking the list of nodes in the system
+// and aggregating a Global Router Interface to each of the nodes.
+//
+  void
+GlobalRouteManagerImpl::SelectRouterNodes () 
+{
+  NS_LOG_FUNCTION;
+  for (NodeList::Iterator i = NodeList::Begin (); i != NodeList::End (); i++)
+    {
+      Ptr<Node> node = *i;
+      NS_LOG_LOGIC ("Adding GlobalRouter interface to node " << 
+        node->GetId ());
+
+      Ptr<GlobalRouter> globalRouter = Create<GlobalRouter> (node);
+      node->AddInterface (globalRouter);
+    }
+}
+
+//
+// In order to build the routing database, we need to walk the list of nodes
+// in the system and look for those that support the GlobalRouter interface.
+// These routers will export a number of Link State Advertisements (LSAs)
+// that describe the links and networks that are "adjacent" (i.e., that are
+// on the other side of a point-to-point link).  We take these LSAs and put
+// add them to the Link State DataBase (LSDB) from which the routes will 
+// ultimately be computed.
+//
+  void
+GlobalRouteManagerImpl::BuildGlobalRoutingDatabase () 
+{
+  NS_LOG_FUNCTION;
+//
+// Walk the list of nodes looking for the GlobalRouter Interface.
+//
+  for (NodeList::Iterator i = NodeList::Begin (); i != NodeList::End (); i++)
+    {
+      Ptr<Node> node = *i;
+
+      Ptr<GlobalRouter> rtr = 
+        node->QueryInterface<GlobalRouter> (GlobalRouter::iid);
+//      
+// Ignore nodes that aren't participating in routing.
+//
+      if (!rtr)
+        {
+          continue;
+        }
+//
+// You must call DiscoverLSAs () before trying to use any routing info or to
+// update LSAs.  DiscoverLSAs () drives the process of discovering routes in
+// the GlobalRouter.  Afterward, you may use GetNumLSAs (), which is a very
+// computationally inexpensive call.  If you call GetNumLSAs () before calling 
+// DiscoverLSAs () will get zero as the number since no routes have been 
+// found.
+//
+      uint32_t numLSAs = rtr->DiscoverLSAs ();
+      NS_LOG_LOGIC ("Found " << numLSAs << " LSAs");
+
+      for (uint32_t j = 0; j < numLSAs; ++j)
+        {
+          GlobalRoutingLSA* lsa = new GlobalRoutingLSA ();
+//
+// This is the call to actually fetch a Link State Advertisement from the 
+// router.
+//
+          rtr->GetLSA (j, *lsa);
+          NS_LOG_LOGIC (*lsa);
+//
+// Write the newly discovered link state advertisement to the database.
+//
+          m_lsdb->Insert (lsa->GetLinkStateId (), lsa); 
+        }
+    }
+}
+
+//
+// For each node that is a global router (which is determined by the presence
+// of an aggregated GlobalRouter interface), run the Dijkstra SPF calculation
+// on the database rooted at that router, and populate the node forwarding
+// tables.
+//
+// This function parallels RFC2328, Section 16.1.1, and quagga ospfd
+//
+// This calculation yields the set of intra-area routes associated
+// with an area (called hereafter Area A).  A router calculates the
+// shortest-path tree using itself as the root.  The formation
+// of the shortest path tree is done here in two stages.  In the
+// first stage, only links between routers and transit networks are
+// considered.  Using the Dijkstra algorithm, a tree is formed from
+// this subset of the link state database.  In the second stage,
+// leaves are added to the tree by considering the links to stub
+// networks.
+//
+// The area's link state database is represented as a directed graph.  
+// The graph's vertices are routers, transit networks and stub networks.  
+//
+// The first stage of the procedure (i.e., the Dijkstra algorithm)
+// can now be summarized as follows. At each iteration of the
+// algorithm, there is a list of candidate vertices.  Paths from
+// the root to these vertices have been found, but not necessarily
+// the shortest ones.  However, the paths to the candidate vertex
+// that is closest to the root are guaranteed to be shortest; this
+// vertex is added to the shortest-path tree, removed from the
+// candidate list, and its adjacent vertices are examined for
+// possible addition to/modification of the candidate list.  The
+// algorithm then iterates again.  It terminates when the candidate
+// list becomes empty. 
+//
+  void
+GlobalRouteManagerImpl::InitializeRoutes ()
+{
+  NS_LOG_FUNCTION;
+//
+// Walk the list of nodes in the system.
+//
+  for (NodeList::Iterator i = NodeList::Begin (); i != NodeList::End (); i++)
+    {
+      Ptr<Node> node = *i;
+//
+// Look for the GlobalRouter interface that indicates that the node is
+// participating in routing.
+//
+      Ptr<GlobalRouter> rtr = 
+        node->QueryInterface<GlobalRouter> (GlobalRouter::iid);
+//
+// if the node has a global router interface, then run the global routing
+// algorithms.
+//
+      if (rtr && rtr->GetNumLSAs () )
+        {
+          SPFCalculate (rtr->GetRouterId ());
+        }
+    }
+}
+
+//
+// This method is derived from quagga ospf_spf_next ().  See RFC2328 Section 
+// 16.1 (2) for further details.
+//
+// We're passed a parameter <v> that is a vertex which is already in the SPF
+// tree.  A vertex represents a router node.  We also get a reference to the
+// SPF candidate queue, which is a priority queue containing the shortest paths
+// to the networks we know about.
+//
+// We examine the links in v's LSA and update the list of candidates with any
+// vertices not already on the list.  If a lower-cost path is found to a
+// vertex already on the candidate list, store the new (lower) cost.
+//
+  void
+GlobalRouteManagerImpl::SPFNext (SPFVertex* v, CandidateQueue& candidate)
+{
+  NS_LOG_FUNCTION;
+
+  SPFVertex* w = 0;
+  GlobalRoutingLSA* w_lsa = 0;
+  GlobalRoutingLinkRecord *l = 0;
+  uint32_t distance = 0;
+  uint32_t numRecordsInVertex = 0;
+//
+// V points to a Router-LSA or Network-LSA
+// Loop over the links in router LSA or attached routers in Network LSA
+//
+  if (v->GetVertexType () == SPFVertex::VertexRouter)
+    {
+      numRecordsInVertex = v->GetLSA ()->GetNLinkRecords (); 
+    }
+  if (v->GetVertexType () == SPFVertex::VertexNetwork)
+    {
+      numRecordsInVertex = v->GetLSA ()->GetNAttachedRouters (); 
+    }
+
+  for (uint32_t i = 0; i < numRecordsInVertex; i++)
+    {
+// Get w_lsa:  In case of V is Router-LSA
+      if (v->GetVertexType () == SPFVertex::VertexRouter) 
+        {
+          NS_LOG_LOGIC ("Examining " << v->GetVertexId () << "'s " <<
+            v->GetLSA ()->GetNLinkRecords () << " link records");
+//
+// (a) If this is a link to a stub network, examine the next link in V's LSA.
+// Links to stub networks will be considered in the second stage of the
+// shortest path calculation.
+//
+          l = v->GetLSA ()->GetLinkRecord (i);
+          if (l->GetLinkType () == GlobalRoutingLinkRecord::StubNetwork)
+            {
+              NS_LOG_LOGIC ("Found a Stub record to " << l->GetLinkId ());
+              continue;
+            }
+//
+// (b) Otherwise, W is a transit vertex (router or transit network).  Look up
+// the vertex W's LSA (router-LSA or network-LSA) in Area A's link state
+// database. 
+//
+          if (l->GetLinkType () == GlobalRoutingLinkRecord::PointToPoint)
+            {
+//
+// Lookup the link state advertisement of the new link -- we call it <w> in
+// the link state database.
+//
+              w_lsa = m_lsdb->GetLSA (l->GetLinkId ());
+              NS_ASSERT (w_lsa);
+              NS_LOG_LOGIC ("Found a P2P record from " << 
+                v->GetVertexId () << " to " << w_lsa->GetLinkStateId ());
+            }
+          else if (l->GetLinkType () == 
+            GlobalRoutingLinkRecord::TransitNetwork)
+            {
+              w_lsa = m_lsdb->GetLSA (l->GetLinkId ());
+              NS_ASSERT (w_lsa);
+              NS_LOG_LOGIC ("Found a Transit record from " << 
+                v->GetVertexId () << " to " << w_lsa->GetLinkStateId ());
+            }
+          else 
+            {
+              NS_ASSERT_MSG (0, "illegal Link Type");
+            }
+        }
+// Get w_lsa:  In case of V is Network-LSA
+      if (v->GetVertexType () == SPFVertex::VertexNetwork) 
+        {
+          w_lsa = m_lsdb->GetLSAByLinkData 
+            (v->GetLSA ()->GetAttachedRouter (i)); 
+          if (!w_lsa)
+            {
+              continue;
+            }
+          NS_LOG_LOGIC ("Found a Network LSA from " << 
+            v->GetVertexId () << " to " << w_lsa->GetLinkStateId ());
+        }
+
+// Note:  w_lsa at this point may be either RouterLSA or NetworkLSA
+//
+// (c) If vertex W is already on the shortest-path tree, examine the next
+// link in the LSA.
+//
+// If the link is to a router that is already in the shortest path first tree
+// then we have it covered -- ignore it.
+//
+      if (w_lsa->GetStatus () == GlobalRoutingLSA::LSA_SPF_IN_SPFTREE) 
+        {
+          NS_LOG_LOGIC ("Skipping ->  LSA "<< 
+            w_lsa->GetLinkStateId () << " already in SPF tree");
+          continue;
+        }
+//
+// (d) Calculate the link state cost D of the resulting path from the root to 
+// vertex W.  D is equal to the sum of the link state cost of the (already 
+// calculated) shortest path to vertex V and the advertised cost of the link
+// between vertices V and W.  
+//
+      if (v->GetLSA ()->GetLSType () == GlobalRoutingLSA::RouterLSA)
+        {
+          distance = v->GetDistanceFromRoot () + l->GetMetric ();
+        }
+      else
+        {
+          distance = v->GetDistanceFromRoot ();
+        }
+
+      NS_LOG_LOGIC ("Considering w_lsa " << w_lsa->GetLinkStateId ());
+
+// Is there already vertex w in candidate list?
+      if (w_lsa->GetStatus () == GlobalRoutingLSA::LSA_SPF_NOT_EXPLORED)
+        {
+
+// prepare vertex w
+          w = new SPFVertex (w_lsa);
+// Calculate nexthop to w
+// We need to figure out how to actually get to the new router represented
+// by <w>.  This will (among other things) find the next hop address to send
+// packets destined for this network to, and also find the outbound interface
+// used to forward the packets.
+//
+          if (SPFNexthopCalculation (v, w, l, distance))
+            {
+              w_lsa->SetStatus (GlobalRoutingLSA::LSA_SPF_CANDIDATE);
+//
+// Push this new vertex onto the priority queue (ordered by distance from the
+// root node).
+//
+              candidate.Push (w);
+              NS_LOG_LOGIC ("Pushing " << 
+                w->GetVertexId () << ", parent vertexId: " << 
+                v->GetVertexId ());
+            }
+        }
+      else if (w_lsa->GetStatus () == GlobalRoutingLSA::LSA_SPF_CANDIDATE)
+        {
+//
+// We have already considered the link represented by <w>.  What wse have to
+// do now is to decide if this new router represents a route with a shorter
+// distance metric.
+//
+// So, locate the vertex in the candidate queue and take a look at the 
+// distance.
+          w = candidate.Find (w_lsa->GetLinkStateId ());
+          if (w->GetDistanceFromRoot () < distance)
+            {
+//
+// This is not a shorter path, so don't do anything.
+//
+              continue;
+            }
+          else if (w->GetDistanceFromRoot () == distance)
+            {
+//
+// This path is one with an equal cost.  Do nothing for now -- we're not doing
+// equal-cost multipath cases yet.
+//
+            }
+          else
+            {
+// 
+// this path represents a new, lower-cost path to <w> (the vertex we found in
+// the current link record of the link state advertisement of the current root
+// (vertex <v>)
+//
+// N.B. the nexthop_calculation is conditional, if it finds a valid nexthop
+// it will call spf_add_parents, which will flush the old parents
+//
+              if (SPFNexthopCalculation (v, w, l, distance))
+                {
+//
+// If we've changed the cost to get to the vertex represented by <w>, we 
+// must reorder the priority queue keyed to that cost.
+//
+                  candidate.Reorder ();
+                }
+            } // new lower cost path found   
+        } // end W is already on the candidate list
+    } // end loop over the links in V's LSA
+}
+
+//
+// This method is derived from quagga ospf_next_hop_calculation() 16.1.1.  
+//
+// Calculate nexthop from root through V (parent) to vertex W (destination)
+// with given distance from root->W.
+//
+// As appropriate, set w's parent, distance, and nexthop information
+//
+// For now, this is greatly simplified from the quagga code
+//                  
+  int
+GlobalRouteManagerImpl::SPFNexthopCalculation (
+  SPFVertex* v, 
+  SPFVertex* w,
+  GlobalRoutingLinkRecord* l,
+  uint32_t distance)
+{
+  NS_LOG_FUNCTION;
+//
+// If w is a NetworkVertex, l should be null
+/*
+  if (w->GetVertexType () == SPFVertex::VertexNetwork && l)
+    {
+        NS_ASSERT_MSG(0, "Error:  SPFNexthopCalculation parameter problem");
+    }
+*/
+
+//
+// The vertex m_spfroot is a distinguished vertex representing the node at
+// the root of the calculations.  That is, it is the node for which we are
+// calculating the routes.
+//
+// There are two distinct cases for calculating the next hop information.
+// First, if we're considering a hop from the root to an "adjacent" network
+// (one that is on the other side of a point-to-point link connected to the
+// root), then we need to store the information needed to forward down that
+// link.  The second case is if the network is not directly adjacent.  In that
+// case we need to use the forwarding information from the vertex on the path
+// to the destination that is directly adjacent [node 1] in both cases of the
+// diagram below.
+// 
+// (1) [root] -> [point-to-point] -> [node 1]
+// (2) [root] -> [point-to-point] -> [node 1] -> [point-to-point] -> [node 2]
+//
+// We call the propagation of next hop information down vertices of a path
+// "inheriting" the next hop information.
+//
+// The point-to-point link information is only useful in this calculation when
+// we are examining the root node. 
+//
+  if (v == m_spfroot)
+    {
+//
+// In this case <v> is the root node, which means it is the starting point
+// for the packets forwarded by that node.  This also means that the next hop
+// address of packets headed for some arbitrary off-network destination must
+// be the destination at the other end of one of the links off of the root
+// node if this root node is a router.  We then need to see if this node <w>
+// is a router.
+//
+      if (w->GetVertexType () == SPFVertex::VertexRouter) 
+        {
+//
+// In the case of point-to-point links, the link data field (m_linkData) of a
+// Global Router Link Record contains the local IP address.  If we look at the
+// link record describing the link from the perspecive of <w> (the remote
+// node from the viewpoint of <v>) back to the root node, we can discover the
+// IP address of the router to which <v> is adjacent.  This is a distinguished
+// address -- the next hop address to get from <v> to <w> and all networks 
+// accessed through that path.
+//
+// SPFGetNextLink () is a little odd.  used in this way it is just going to
+// return the link record describing the link from <w> to <v>.  Think of it as
+// SPFGetLink.
+//
+          NS_ASSERT(l);
+          GlobalRoutingLinkRecord *linkRemote = 0;
+          linkRemote = SPFGetNextLink (w, v, linkRemote);
+// 
+// At this point, <l> is the Global Router Link Record describing the point-
+// to point link from <v> to <w> from the perspective of <v>; and <linkRemote>
+// is the Global Router Link Record describing that same link from the 
+// perspective of <w> (back to <v>).  Now we can just copy the next hop 
+// address from the m_linkData member variable.
+// 
+// The next hop member variable we put in <w> has the sense "in order to get
+// from the root node to the host represented by vertex <w>, you have to send
+// the packet to the next hop address specified in w->m_nextHop.
+//
+          w->SetNextHop(linkRemote->GetLinkData ());
+// 
+// Now find the outgoing interface corresponding to the point to point link
+// from the perspective of <v> -- remember that <l> is the link "from"
+// <v> "to" <w>.
+//
+          w->SetOutgoingInterfaceId (
+            FindOutgoingInterfaceId (l->GetLinkData ()));
+
+          NS_LOG_LOGIC ("Next hop from " << 
+            v->GetVertexId () << " to " << w->GetVertexId () << 
+            " goes through next hop " << w->GetNextHop () <<
+            " via outgoing interface " << w->GetOutgoingInterfaceId ());
+        }  // end W is a router vertes
+      else 
+        {
+          NS_ASSERT (w->GetVertexType () == SPFVertex::VertexNetwork);
+// W is a directly connected network; no next hop is required
+          GlobalRoutingLSA* w_lsa = w->GetLSA ();
+          NS_ASSERT (w_lsa->GetLSType () == GlobalRoutingLSA::NetworkLSA);
+// Find outgoing interface ID for this network
+          w->SetOutgoingInterfaceId (
+            FindOutgoingInterfaceId (w_lsa->GetLinkStateId (), 
+            w_lsa->GetNetworkLSANetworkMask () ));
+          w->SetDistanceFromRoot (distance);
+          w->SetParent (v);
+          NS_LOG_LOGIC ("Next hop from " << 
+            v->GetVertexId () << " to network " << w->GetVertexId () << 
+            " via outgoing interface " << w->GetOutgoingInterfaceId ());
+          return 1;
+        }
+    } // end v is the root
+  else if (v->GetVertexType () == SPFVertex::VertexNetwork) 
+    {
+// See if any of v's parents are the root
+      if (v->GetParent () == m_spfroot)
+        {
+// 16.1.1 para 5. ...the parent vertex is a network that
+// directly connects the calculating router to the destination
+// router.  The list of next hops is then determined by
+// examining the destination's router-LSA...
+          NS_ASSERT (w->GetVertexType () == SPFVertex::VertexRouter);
+          GlobalRoutingLinkRecord *linkRemote = 0;
+          while ((linkRemote = SPFGetNextLink (w, v, linkRemote)))
+            {
+/* ...For each link in the router-LSA that points back to the
+ * parent network, the link's Link Data field provides the IP
+ * address of a next hop router.  The outgoing interface to
+ * use can then be derived from the next hop IP address (or 
+ * it can be inherited from the parent network).
+ */
+                w->SetNextHop(linkRemote->GetLinkData ());
+                w->SetOutgoingInterfaceId (v->GetOutgoingInterfaceId ());
+                NS_LOG_LOGIC ("Next hop from " << 
+                  v->GetVertexId () << " to " << w->GetVertexId () << 
+                  " goes through next hop " << w->GetNextHop () <<
+                  " via outgoing interface " << w->GetOutgoingInterfaceId ());
+            }
+        }
+      else 
+        {
+          w->SetNextHop (v->GetNextHop ());
+          w->SetOutgoingInterfaceId (v->GetOutgoingInterfaceId ());
+        }
+    }
+  else 
+    {
+//
+// If we're calculating the next hop information from a node (v) that is 
+// *not* the root, then we need to "inherit" the information needed to
+// forward the packet from the vertex closer to the root.  That is, we'll
+// still send packets to the next hop address of the router adjacent to the
+// root on the path toward <w>.
+//
+// Above, when we were considering the root node, we calculated the next hop
+// address and outgoing interface required to get off of the root network.  
+// At this point, we are further away from the root network along one of the
+// (shortest) paths.  So the next hop and outoing interface remain the same
+// (are inherited).
+//
+      w->SetNextHop (v->GetNextHop ());
+      w->SetOutgoingInterfaceId (v->GetOutgoingInterfaceId ());
+    }
+//
+// In all cases, we need valid values for the distance metric and a parent.
+//
+  w->SetDistanceFromRoot (distance);
+  w->SetParent (v);
+
+  return 1;
+}
+
+//
+// This method is derived from quagga ospf_get_next_link ()
+//
+// First search the Global Router Link Records of vertex <v> for one
+// representing a point-to point link to vertex <w>.
+//
+// What is done depends on prev_link.  Contrary to appearances, prev_link just
+// acts as a flag here.  If prev_link is NULL, we return the first Global
+// Router Link Record we find that describes a point-to-point link from <v> 
+// to <w>.  If prev_link is not NULL, we return a Global Router Link Record
+// representing a possible *second* link from <v> to <w>.
+//
+  GlobalRoutingLinkRecord* 
+GlobalRouteManagerImpl::SPFGetNextLink (
+  SPFVertex* v,
+  SPFVertex* w,
+  GlobalRoutingLinkRecord* prev_link) 
+{
+  NS_LOG_FUNCTION;
+
+  bool skip = true;
+  bool found_prev_link = false;
+  GlobalRoutingLinkRecord* l;
+//
+// If prev_link is 0, we are really looking for the first link, not the next 
+// link.
+//
+  if (prev_link == 0)
+    {
+      skip = false;
+      found_prev_link = true;
+    }
+//  
+// Iterate through the Global Router Link Records advertised by the vertex
+// <v> looking for records representing the point-to-point links off of this
+// vertex.
+//
+  for (uint32_t i = 0; i < v->GetLSA ()->GetNLinkRecords (); ++i)
+    {
+      l = v->GetLSA ()->GetLinkRecord (i);
+//
+// The link ID of a link record representing a point-to-point link is set to
+// the router ID of the neighboring router -- the router to which the link
+// connects from the perspective of <v> in this case.  The vertex ID is also
+// set to the router ID (using the link state advertisement of a router node).
+// We're just checking to see if the link <l> is actually the link from <v> to
+// <w>.
+//
+      if (l->GetLinkId () == w->GetVertexId ()) 
+        {
+          if (!found_prev_link)
+            {
+              NS_LOG_LOGIC ("Skipping links before prev_link found");
+              found_prev_link = true;
+              continue;
+            }
+        
+          NS_LOG_LOGIC ("Found matching link l:  linkId = " <<
+          l->GetLinkId () << " linkData = " << l->GetLinkData ());
+//
+// If skip is false, don't (not too surprisingly) skip the link found -- it's 
+// the one we're interested in.  That's either because we didn't pass in a 
+// previous link, and we're interested in the first one, or because we've 
+// skipped a previous link and moved forward to the next (which is then the
+// one we want).
+//
+        if (skip == false) 
+          {
+            NS_LOG_LOGIC ("Returning the found link");
+            return l;
+          }
+        else
+          {
+//
+// Skip is true and we've found a link from <v> to <w>.  We want the next one.
+// Setting skip to false gets us the next point-to-point global router link
+// record in the LSA from <v>.
+//
+            NS_LOG_LOGIC ("Skipping the found link");
+            skip = false;
+            continue;
+          }
+      }
+    }
+  return 0;
+}
+  
+//
+// Used for unit tests.
+//
+  void
+GlobalRouteManagerImpl::DebugSPFCalculate (Ipv4Address root)
+{
+  NS_LOG_FUNCTION;
+  SPFCalculate (root);
+}
+
+// quagga ospf_spf_calculate
+  void
+GlobalRouteManagerImpl::SPFCalculate (Ipv4Address root)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << root << ")");
+
+  SPFVertex *v;
+//
+// Initialize the Link State Database.
+//
+  m_lsdb->Initialize ();
+//
+// The candidate queue is a priority queue of SPFVertex objects, with the top
+// of the queue being the closest vertex in terms of distance from the root
+// of the tree.  Initially, this queue is empty.
+//
+  CandidateQueue candidate;
+  NS_ASSERT(candidate.Size () == 0);
+//
+// Initialize the shortest-path tree to only contain the router doing the 
+// calculation.  Each router (and corresponding network) is a vertex in the
+// shortest path first (SPF) tree.
+//
+  v = new SPFVertex (m_lsdb->GetLSA (root));
+// 
+// This vertex is the root of the SPF tree and it is distance 0 from the root.
+// We also mark this vertex as being in the SPF tree.
+//
+  m_spfroot= v;
+  v->SetDistanceFromRoot (0);
+  v->GetLSA ()->SetStatus (GlobalRoutingLSA::LSA_SPF_IN_SPFTREE);
+
+  for (;;)
+    {
+//
+// The operations we need to do are given in the OSPF RFC which we reference
+// as we go along.
+//
+// RFC2328 16.1. (2). 
+//
+// We examine the Global Router Link Records in the Link State 
+// Advertisements of the current vertex.  If there are any point-to-point
+// links to unexplored adjacent vertices we add them to the tree and update
+// the distance and next hop information on how to get there.  We also add
+// the new vertices to the candidate queue (the priority queue ordered by
+// shortest path).  If the new vertices represent shorter paths, we use them
+// and update the path cost.
+//
+      SPFNext (v, candidate);
+//
+// RFC2328 16.1. (3). 
+//
+// If at this step the candidate list is empty, the shortest-path tree (of
+// transit vertices) has been completely built and this stage of the
+// procedure terminates. 
+//
+      if (candidate.Size () == 0)
+        {
+          break;
+        }
+//
+// Choose the vertex belonging to the candidate list that is closest to the
+// root, and add it to the shortest-path tree (removing it from the candidate
+// list in the process).
+//
+// Recall that in the previous step, we created SPFVertex structures for each
+// of the routers found in the Global Router Link Records and added tehm to 
+// the candidate list.
+//
+      v = candidate.Pop ();
+      NS_LOG_LOGIC ("Popped vertex " << v->GetVertexId ());
+//
+// Update the status field of the vertex to indicate that it is in the SPF
+// tree.
+//
+      v->GetLSA ()->SetStatus (GlobalRoutingLSA::LSA_SPF_IN_SPFTREE);
+//
+// The current vertex has a parent pointer.  By calling this rather oddly 
+// named method (blame quagga) we add the current vertex to the list of 
+// children of that parent vertex.  In the next hop calculation called during
+// SPFNext, the parent pointer was set but the vertex has been orphaned up
+// to now.
+//
+      SPFVertexAddParent (v);
+//
+// Note that when there is a choice of vertices closest to the root, network
+// vertices must be chosen before router vertices in order to necessarily
+// find all equal-cost paths. We don't do this at this moment, we should add
+// the treatment above codes. -- kunihiro. 
+//
+// RFC2328 16.1. (4). 
+//
+// This is the method that actually adds the routes.  It'll walk the list
+// of nodes in the system, looking for the node corresponding to the router
+// ID of the root of the tree -- that is the router we're building the routes
+// for.  It looks for the Ipv4 interface of that node and remembers it.  So
+// we are only actually adding routes to that one node at the root of the SPF 
+// tree.
+//
+// We're going to pop of a pointer to every vertex in the tree except the 
+// root in order of distance from the root.  For each of the vertices, we call
+// SPFIntraAddRouter ().  Down in SPFIntraAddRouter, we look at all of the 
+// point-to-point Global Router Link Records (the links to nodes adjacent to
+// the node represented by the vertex).  We add a route to the IP address 
+// specified by the m_linkData field of each of those link records.  This will
+// be the *local* IP address associated with the interface attached to the 
+// link.  We use the outbound interface and next hop information present in 
+// the vertex <v> which have possibly been inherited from the root.
+//
+// To summarize, we're going to look at the node represented by <v> and loop
+// through its point-to-point links, adding a *host* route to the local IP
+// address (at the <v> side) for each of those links.
+//
+      if (v->GetVertexType () == SPFVertex::VertexRouter)
+        {
+          SPFIntraAddRouter (v);
+        }
+      else if (v->GetVertexType () == SPFVertex::VertexNetwork)
+        {
+          SPFIntraAddTransit (v);
+        }
+      else
+        {
+          NS_ASSERT_MSG(0, "illegal SPFVertex type");
+        }
+//
+// RFC2328 16.1. (5). 
+//
+// Iterate the algorithm by returning to Step 2 until there are no more
+// candidate vertices.
+//
+    }
+//
+// Second stage of SPF calculation procedure's  
+// NOTYET:  ospf_spf_process_stubs (area, area->spf, new_table);
+//
+// We're all done setting the routing information for the node at the root of
+// the SPF tree.  Delete all of the vertices and corresponding resources.  Go
+// possibly do it again for the next router.
+//
+  delete m_spfroot;
+  m_spfroot = 0;
+}
+
+//
+// Return the interface index corresponding to a given IP address
+// This is a wrapper around GetIfIndexByIpv4Address(), but we first
+// have to find the right node pointer to pass to that function.
+//
+  uint32_t
+GlobalRouteManagerImpl::FindOutgoingInterfaceId (Ipv4Address a, Ipv4Mask amask)
+{
+  NS_LOG_FUNCTION;
+//
+// We have an IP address <a> and a vertex ID of the root of the SPF tree.  
+// The question is what interface index does this address correspond to.
+// The answer is a little complicated since we have to find a pointer to
+// the node corresponding to the vertex ID, find the Ipv4 interface on that
+// node in order to iterate the interfaces and find the one corresponding to
+// the address in question.
+//
+  Ipv4Address routerId = m_spfroot->GetVertexId ();
+//
+// Walk the list of nodes in the system looking for the one corresponding to
+// the node at the root of the SPF tree.  This is the node for which we are
+// building the routing table.
+//
+  NodeList::Iterator i = NodeList::Begin (); 
+  for (; i != NodeList::End (); i++)
+    {
+      Ptr<Node> node = *i;
+
+      Ptr<GlobalRouter> rtr = 
+        node->QueryInterface<GlobalRouter> (GlobalRouter::iid);
+//
+// If the node doesn't have a GlobalRouter interface it can't be the one
+// we're interested in.
+//
+      if (rtr == 0)
+        {
+          continue;
+        }
+
+      if (rtr->GetRouterId () == routerId)
+        {
+//
+// This is the node we're building the routing table for.  We're going to need
+// the Ipv4 interface to look for the ipv4 interface index.  Since this node
+// is participating in routing IP version 4 packets, it certainly must have 
+// an Ipv4 interface.
+//
+          Ptr<Ipv4> ipv4 = node->QueryInterface<Ipv4> (Ipv4::iid);
+          NS_ASSERT_MSG (ipv4, 
+            "GlobalRouteManagerImpl::FindOutgoingInterfaceId (): "
+            "QI for <Ipv4> interface failed");
+//
+// Look through the interfaces on this node for one that has the IP address
+// we're looking for.  If we find one, return the corresponding interface
+// index.
+//
+          return (Ipv4::GetIfIndexByAddress (node, a, amask) );
+        }
+    }
+//
+// Couldn't find it.
+//
+  return 0;
+}
+
+//
+// This method is derived from quagga ospf_intra_add_router ()
+//
+// This is where we are actually going to add the host routes to the routing
+// tables of the individual nodes.
+//
+// The vertex passed as a parameter has just been added to the SPF tree.
+// This vertex must have a valid m_root_oid, corresponding to the outgoing
+// interface on the root router of the tree that is the first hop on the path
+// to the vertex.  The vertex must also have a next hop address, corresponding
+// to the next hop on the path to the vertex.  The vertex has an m_lsa field
+// that has some number of link records.  For each point to point link record,
+// the m_linkData is the local IP address of the link.  This corresponds to
+// a destination IP address, reachable from the root, to which we add a host
+// route.
+//
+  void
+GlobalRouteManagerImpl::SPFIntraAddRouter (SPFVertex* v)
+{
+  NS_LOG_FUNCTION;
+
+  NS_ASSERT_MSG (m_spfroot, 
+    "GlobalRouteManagerImpl::SPFIntraAddRouter (): Root pointer not set");
+//
+// The root of the Shortest Path First tree is the router to which we are 
+// going to write the actual routing table entries.  The vertex corresponding
+// to this router has a vertex ID which is the router ID of that node.  We're
+// going to use this ID to discover which node it is that we're actually going
+// to update.
+//
+  Ipv4Address routerId = m_spfroot->GetVertexId ();
+
+  NS_LOG_LOGIC ("Vertex ID = " << routerId);
+//
+// We need to walk the list of nodes looking for the one that has the router
+// ID corresponding to the root vertex.  This is the one we're going to write
+// the routing information to.
+//
+  NodeList::Iterator i = NodeList::Begin (); 
+  for (; i != NodeList::End (); i++)
+    {
+      Ptr<Node> node = *i;
+//
+// The router ID is accessible through the GlobalRouter interface, so we need
+// to QI for that interface.  If there's no GlobalRouter interface, the node
+// in question cannot be the router we want, so we continue.
+// 
+      Ptr<GlobalRouter> rtr = 
+        node->QueryInterface<GlobalRouter> (GlobalRouter::iid);
+
+      if (rtr == 0)
+        {
+          NS_LOG_LOGIC ("No GlobalRouter interface on node " << 
+            node->GetId ());
+          continue;
+        }
+//
+// If the router ID of the current node is equal to the router ID of the 
+// root of the SPF tree, then this node is the one for which we need to 
+// write the routing tables.
+//
+      NS_LOG_LOGIC ("Considering router " << rtr->GetRouterId ());
+
+      if (rtr->GetRouterId () == routerId)
+        {
+          NS_LOG_LOGIC ("Setting routes for node " << node->GetId ());
+//
+// Routing information is updated using the Ipv4 interface.  We need to QI
+// for that interface.  If the node is acting as an IP version 4 router, it
+// should absolutely have an Ipv4 interface.
+//
+          Ptr<Ipv4> ipv4 = node->QueryInterface<Ipv4> (Ipv4::iid);
+          NS_ASSERT_MSG (ipv4, 
+            "GlobalRouteManagerImpl::SPFIntraAddRouter (): "
+            "QI for <Ipv4> interface failed");
+//
+// Get the Global Router Link State Advertisement from the vertex we're
+// adding the routes to.  The LSA will have a number of attached Global Router
+// Link Records corresponding to links off of that vertex / node.  We're going
+// to be interested in the records corresponding to point-to-point links.
+//
+          GlobalRoutingLSA *lsa = v->GetLSA ();
+          NS_ASSERT_MSG (lsa, 
+            "GlobalRouteManagerImpl::SPFIntraAddRouter (): "
+            "Expected valid LSA in SPFVertex* v");
+
+          uint32_t nLinkRecords = lsa->GetNLinkRecords ();
+//
+// Iterate through the link records on the vertex to which we're going to add
+// routes.  To make sure we're being clear, we're going to add routing table
+// entries to the tables on the node corresping to the root of the SPF tree.
+// These entries will have routes to the IP addresses we find from looking at
+// the local side of the point-to-point links found on the node described by
+// the vertex <v>.
+//
+          for (uint32_t j = 0; j < nLinkRecords; j += 2)
+            {
+//
+// We are only concerned about point-to-point links
+//
+              GlobalRoutingLinkRecord *lr = lsa->GetLinkRecord (j);
+              if (lr->GetLinkType () != GlobalRoutingLinkRecord::PointToPoint)
+                {
+                  continue;
+                }
+
+              NS_LOG_LOGIC (" Node " << node->GetId () <<
+                " add route to " << lr->GetLinkData () <<
+                " using next hop " << v->GetNextHop () <<
+                " via interface " << v->GetOutgoingInterfaceId ());
+//
+// Here's why we did all of that work.  We're going to add a host route to the
+// host address found in the m_linkData field of the point-to-point link
+// record.  In the case of a point-to-point link, this is the local IP address
+// of the node connected to the link.  Each of these point-to-point links
+// will correspond to a local interface that has an IP address to which
+// the node at the root of the SPF tree can send packets.  The vertex <v> 
+// (corresponding to the node that has these links and interfaces) has 
+// an m_nextHop address precalculated for us that is the address to which the
+// root node should send packets to be forwarded to these IP addresses.
+// Similarly, the vertex <v> has an m_rootOif (outbound interface index) to
+// which the packets should be send for forwarding.
+//
+              ipv4->AddHostRouteTo (lr->GetLinkData (), v->GetNextHop (),
+                v->GetOutgoingInterfaceId ());
+            }
+//
+// Done adding the routes for the selected node.
+//
+          return;
+        }
+    }
+}
+  void
+GlobalRouteManagerImpl::SPFIntraAddTransit (SPFVertex* v)
+{
+  NS_LOG_FUNCTION;
+
+  NS_ASSERT_MSG (m_spfroot, 
+    "GlobalRouteManagerImpl::SPFIntraAddTransit (): Root pointer not set");
+//
+// The root of the Shortest Path First tree is the router to which we are 
+// going to write the actual routing table entries.  The vertex corresponding
+// to this router has a vertex ID which is the router ID of that node.  We're
+// going to use this ID to discover which node it is that we're actually going
+// to update.
+//
+  Ipv4Address routerId = m_spfroot->GetVertexId ();
+
+  NS_LOG_LOGIC ("Vertex ID = " << routerId);
+//
+// We need to walk the list of nodes looking for the one that has the router
+// ID corresponding to the root vertex.  This is the one we're going to write
+// the routing information to.
+//
+  NodeList::Iterator i = NodeList::Begin (); 
+  for (; i != NodeList::End (); i++)
+    {
+      Ptr<Node> node = *i;
+//
+// The router ID is accessible through the GlobalRouter interface, so we need
+// to QI for that interface.  If there's no GlobalRouter interface, the node
+// in question cannot be the router we want, so we continue.
+// 
+      Ptr<GlobalRouter> rtr = 
+        node->QueryInterface<GlobalRouter> (GlobalRouter::iid);
+
+      if (rtr == 0)
+        {
+          NS_LOG_LOGIC ("No GlobalRouter interface on node " << 
+            node->GetId ());
+          continue;
+        }
+//
+// If the router ID of the current node is equal to the router ID of the 
+// root of the SPF tree, then this node is the one for which we need to 
+// write the routing tables.
+//
+      NS_LOG_LOGIC ("Considering router " << rtr->GetRouterId ());
+
+      if (rtr->GetRouterId () == routerId)
+        {
+          NS_LOG_LOGIC ("setting routes for node " << node->GetId ());
+//
+// Routing information is updated using the Ipv4 interface.  We need to QI
+// for that interface.  If the node is acting as an IP version 4 router, it
+// should absolutely have an Ipv4 interface.
+//
+          Ptr<Ipv4> ipv4 = node->QueryInterface<Ipv4> (Ipv4::iid);
+          NS_ASSERT_MSG (ipv4, 
+            "GlobalRouteManagerImpl::SPFIntraAddTransit (): "
+            "QI for <Ipv4> interface failed");
+//
+// Get the Global Router Link State Advertisement from the vertex we're
+// adding the routes to.  The LSA will have a number of attached Global Router
+// Link Records corresponding to links off of that vertex / node.  We're going
+// to be interested in the records corresponding to point-to-point links.
+//
+          GlobalRoutingLSA *lsa = v->GetLSA ();
+          NS_ASSERT_MSG (lsa, 
+            "GlobalRouteManagerImpl::SPFIntraAddTransit (): "
+            "Expected valid LSA in SPFVertex* v");
+          Ipv4Mask tempmask = lsa->GetNetworkLSANetworkMask ();
+          Ipv4Address tempip = lsa->GetLinkStateId ();
+          tempip = tempip.CombineMask (tempmask);
+          ipv4->AddNetworkRouteTo (tempip, tempmask, v->GetNextHop (),
+            v->GetOutgoingInterfaceId ());
+          NS_LOG_LOGIC ("Node " << node->GetId () <<
+            " add network route to " << tempip <<
+            " using next hop " << v->GetNextHop () <<
+            " via interface " << v->GetOutgoingInterfaceId ());
+        }
+    } 
+}
+
+// Derived from quagga ospf_vertex_add_parents ()
+//
+// This is a somewhat oddly named method (blame quagga).  Although you might
+// expect it to add a parent *to* something, it actually adds a vertex
+// to the list of children *in* each of its parents. 
+//
+// Given a pointer to a vertex, it links back to the vertex's parent that it
+// already has set and adds itself to that vertex's list of children.
+//
+// For now, only one parent (not doing equal-cost multipath)
+//
+  void
+GlobalRouteManagerImpl::SPFVertexAddParent (SPFVertex* v)
+{
+  NS_LOG_FUNCTION;
+  v->GetParent ()->AddChild (v);
+}
+
+} // namespace ns3
+
+#ifdef RUN_SELF_TESTS
+
+// ---------------------------------------------------------------------------
+//
+// Unit Tests
+//
+// ---------------------------------------------------------------------------
+
+#include "ns3/test.h"
+#include "ns3/simulator.h"
+
+namespace ns3 {
+
+class GlobalRouteManagerImplTest : public Test {
+public:
+  GlobalRouteManagerImplTest ();
+  virtual ~GlobalRouteManagerImplTest ();
+  virtual bool RunTests (void);
+};
+
+GlobalRouteManagerImplTest::GlobalRouteManagerImplTest ()
+  : Test ("GlobalRouteManagerImpl")
+{
+}
+
+GlobalRouteManagerImplTest::~GlobalRouteManagerImplTest ()
+{}
+
+  bool
+GlobalRouteManagerImplTest::RunTests (void)
+{
+  bool ok = true;
+
+  CandidateQueue candidate;
+
+  for (int i = 0; i < 100; ++i)
+    {
+      SPFVertex *v = new SPFVertex;
+      v->SetDistanceFromRoot (rand () % 100);
+      candidate.Push (v);
+    }
+
+  uint32_t lastDistance = 0;
+
+  for (int i = 0; i < 100; ++i)
+    {
+      SPFVertex *v = candidate.Pop ();
+      if (v->GetDistanceFromRoot () < lastDistance)
+        {
+          ok = false;
+        }
+      lastDistance = v->GetDistanceFromRoot ();
+      delete v;
+      v = 0;
+    }
+
+  // Build fake link state database; four routers (0-3), 3 point-to-point
+  // links
+  //
+  //   n0
+  //      \ link 0
+  //       \          link 2
+  //        n2 -------------------------n3
+  //       /
+  //      / link 1
+  //    n1
+  //
+  //  link0:  10.1.1.1/30, 10.1.1.2/30
+  //  link1:  10.1.2.1/30, 10.1.2.2/30
+  //  link2:  10.1.3.1/30, 10.1.3.2/30
+  //
+  // Router 0
+  GlobalRoutingLinkRecord* lr0 = new GlobalRoutingLinkRecord (
+    GlobalRoutingLinkRecord::PointToPoint, 
+    "0.0.0.2",  // router ID 0.0.0.2
+    "10.1.1.1", // local ID
+    1);         // metric
+
+  GlobalRoutingLinkRecord* lr1 = new GlobalRoutingLinkRecord (
+    GlobalRoutingLinkRecord::StubNetwork,
+    "10.1.1.1",
+    "255.255.255.252",
+    1);
+
+  GlobalRoutingLSA* lsa0 = new GlobalRoutingLSA ();
+  lsa0->SetLSType (GlobalRoutingLSA::RouterLSA);
+  lsa0->SetLinkStateId ("0.0.0.0");
+  lsa0->SetAdvertisingRouter ("0.0.0.0");
+  lsa0->AddLinkRecord (lr0);
+  lsa0->AddLinkRecord (lr1);
+
+  // Router 1
+  GlobalRoutingLinkRecord* lr2 = new GlobalRoutingLinkRecord (
+    GlobalRoutingLinkRecord::PointToPoint,
+    "0.0.0.2",
+    "10.1.2.1",
+    1);
+
+  GlobalRoutingLinkRecord* lr3 = new GlobalRoutingLinkRecord (
+    GlobalRoutingLinkRecord::StubNetwork,
+    "10.1.2.1",
+    "255.255.255.252",
+    1);
+
+  GlobalRoutingLSA* lsa1 = new GlobalRoutingLSA ();
+  lsa1->SetLSType (GlobalRoutingLSA::RouterLSA);
+  lsa1->SetLinkStateId ("0.0.0.1");
+  lsa1->SetAdvertisingRouter ("0.0.0.1");
+  lsa1->AddLinkRecord (lr2);
+  lsa1->AddLinkRecord (lr3);
+  
+  // Router 2 
+  GlobalRoutingLinkRecord* lr4 = new GlobalRoutingLinkRecord (
+    GlobalRoutingLinkRecord::PointToPoint,
+    "0.0.0.0",
+    "10.1.1.2",
+    1);
+
+  GlobalRoutingLinkRecord* lr5 = new GlobalRoutingLinkRecord (
+    GlobalRoutingLinkRecord::StubNetwork,
+    "10.1.1.2",
+    "255.255.255.252",
+    1);
+
+  GlobalRoutingLinkRecord* lr6 = new GlobalRoutingLinkRecord (
+    GlobalRoutingLinkRecord::PointToPoint,
+    "0.0.0.1",
+    "10.1.2.2",
+    1);
+
+  GlobalRoutingLinkRecord* lr7 = new GlobalRoutingLinkRecord (
+    GlobalRoutingLinkRecord::StubNetwork,
+    "10.1.2.2",
+    "255.255.255.252",
+    1);
+
+  GlobalRoutingLinkRecord* lr8 = new GlobalRoutingLinkRecord (
+    GlobalRoutingLinkRecord::PointToPoint,
+    "0.0.0.3",
+    "10.1.3.2",
+    1);
+
+  GlobalRoutingLinkRecord* lr9 = new GlobalRoutingLinkRecord (
+    GlobalRoutingLinkRecord::StubNetwork,
+    "10.1.3.2",
+    "255.255.255.252",
+    1);
+
+  GlobalRoutingLSA* lsa2 = new GlobalRoutingLSA ();
+  lsa2->SetLSType (GlobalRoutingLSA::RouterLSA);
+  lsa2->SetLinkStateId ("0.0.0.2");
+  lsa2->SetAdvertisingRouter ("0.0.0.2");
+  lsa2->AddLinkRecord (lr4);
+  lsa2->AddLinkRecord (lr5);
+  lsa2->AddLinkRecord (lr6);
+  lsa2->AddLinkRecord (lr7);
+  lsa2->AddLinkRecord (lr8);
+  lsa2->AddLinkRecord (lr9);
+
+  // Router 3
+  GlobalRoutingLinkRecord* lr10 = new GlobalRoutingLinkRecord (
+    GlobalRoutingLinkRecord::PointToPoint,
+    "0.0.0.2",
+    "10.1.2.1",
+    1);
+
+  GlobalRoutingLinkRecord* lr11 = new GlobalRoutingLinkRecord (
+    GlobalRoutingLinkRecord::StubNetwork,
+    "10.1.2.1",
+    "255.255.255.252",
+    1);
+
+  GlobalRoutingLSA* lsa3 = new GlobalRoutingLSA ();
+  lsa3->SetLSType (GlobalRoutingLSA::RouterLSA);
+  lsa3->SetLinkStateId ("0.0.0.3");
+  lsa3->SetAdvertisingRouter ("0.0.0.3");
+  lsa3->AddLinkRecord (lr10);
+  lsa3->AddLinkRecord (lr11);
+
+  // Test the database 
+  GlobalRouteManagerLSDB* srmlsdb = new GlobalRouteManagerLSDB ();
+  srmlsdb->Insert (lsa0->GetLinkStateId (), lsa0);
+  srmlsdb->Insert (lsa1->GetLinkStateId (), lsa1);
+  srmlsdb->Insert (lsa2->GetLinkStateId (), lsa2);
+  srmlsdb->Insert (lsa3->GetLinkStateId (), lsa3);
+  NS_ASSERT (lsa2 == srmlsdb->GetLSA (lsa2->GetLinkStateId ()));
+
+  // next, calculate routes based on the manually created LSDB
+  GlobalRouteManagerImpl* srm = new GlobalRouteManagerImpl ();
+  srm->DebugUseLsdb (srmlsdb);  // manually add in an LSDB
+  // Note-- this will succeed without any nodes in the topology
+  // because the NodeList is empty
+  srm->DebugSPFCalculate (lsa0->GetLinkStateId ());  // node n0
+
+  Simulator::Run ();
+
+// XXX here we should do some verification of the routes built
+
+  Simulator::Destroy ();
+
+  // This delete clears the srm, which deletes the LSDB, which clears 
+  // all of the LSAs, which each destroys the attached LinkRecords.
+  delete srm;
+
+  return ok;
+}
+
+// Instantiate this class for the unit tests
+static GlobalRouteManagerImplTest g_globalRouteManagerTest;
+
+} // namespace ns3
+
+#endif 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/routing/global-routing/global-route-manager-impl.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,768 @@
+/* -*- 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
+ *
+ * Authors:  Craig Dowell (craigdo@ee.washington.edu)
+ *           Tom Henderson (tomhend@u.washington.edu)
+ */
+
+#ifndef GLOBAL_ROUTE_MANAGER_IMPL_H
+#define GLOBAL_ROUTE_MANAGER_IMPL_H
+
+#include <stdint.h>
+#include <list>
+#include <queue>
+#include <map>
+#include "ns3/object.h"
+#include "ns3/ptr.h"
+#include "ns3/ipv4-address.h"
+#include "global-router-interface.h"
+
+namespace ns3 {
+
+const uint32_t SPF_INFINITY = 0xffffffff;
+
+class CandidateQueue;
+
+/**
+ * @brief Vertex used in shortest path first (SPF) computations. See RFC 2328,
+ * Section 16.
+ *
+ * Each router in the simulation is associated with an SPFVertex object.  When
+ * calculating routes, each of these routers is, in turn, chosen as the "root"
+ * of the calculation and routes to all of the other routers are eventually
+ * saved in the routing tables of each of the chosen nodes.  Each of these 
+ * routers in the calculation has an associated SPFVertex.
+ *
+ * The "Root" vertex is the SPFVertex representing the router that is having
+ * its routing tables set.  The SPFVertex objects representing other routers
+ * or networks in the simulation are arranged in the SPF tree.  It is this 
+ * tree that represents the Shortest Paths to the other networks.
+ *
+ * Each SPFVertex has a pointer to the Global Router Link State Advertisement
+ * (LSA) that its underlying router has exported.  Within these LSAs are
+ * Global Router Link Records that describe the point to point links from the
+ * underlying router to other nodes (represented by other SPFVertex objects)
+ * in the simulation topology.  The combination of the arrangement of the 
+ * SPFVertex objects in the SPF tree, along with the details of the link
+ * records that connect them provide the information required to construct the
+ * required routes.
+ */
+class SPFVertex
+{
+public:
+/**
+ * @brief Enumeration of the possible types of SPFVertex objects.
+ * @internal
+ *
+ * Currently we use VertexRouter to identify objects that represent a router 
+ * in the simulation topology, and VertexNetwork to identify objects that 
+ * represent a network.
+ */
+  enum VertexType {
+    VertexUnknown = 0,  /**< Uninitialized Link Record */
+    VertexRouter,       /**< Vertex representing a router in the topology */
+    VertexNetwork       /**< Vertex representing a network in the topology */
+  };
+
+/**
+ * @brief Construct an empty ("uninitialized") SPFVertex (Shortest Path First 
+ * Vertex).
+ * @internal
+ *
+ * The Vertex Type is set to VertexUnknown, the Vertex ID is set to 
+ * 255.255.255.255, and the distance from root is set to infinity 
+ * (UINT32_MAX).  The referenced Link State Advertisement (LSA) is set to 
+ * null as is the parent SPFVertex.  The outgoing interface index is set to
+ * infinity, the next hop address is set to 0.0.0.0 and the list of children
+ * of the SPFVertex is initialized to empty.
+ *
+ * @see VertexType
+ */
+  SPFVertex();
+
+/**
+ * @brief Construct an initialized SPFVertex (Shortest Path First Vertex).
+ * @internal
+ *
+ * The Vertex Type is initialized to VertexRouter and the Vertex ID is found
+ * from the Link State ID of the Link State Advertisement (LSA) passed as a
+ * parameter.  The Link State ID is set to the Router ID of the advertising
+ * router.  The referenced LSA (m_lsa) is set to the given LSA.  Other than 
+ * these members, initialization is as in the default constructor.
+ * of the SPFVertex is initialized to empty.
+ *
+ * @see SPFVertex::SPFVertex ()
+ * @see VertexType
+ * @see GlobalRoutingLSA
+ * @param lsa The Link State Advertisement used for finding initial values.
+ */
+  SPFVertex(GlobalRoutingLSA* lsa);
+
+/**
+ * @brief Destroy an SPFVertex (Shortest Path First Vertex).
+ * @internal
+ *
+ * The children vertices of the SPFVertex are recursively deleted.
+ *
+ * @see SPFVertex::SPFVertex ()
+ */
+  ~SPFVertex();
+
+/**
+ * @brief Get the Vertex Type field of a SPFVertex object.
+ * @internal
+ *
+ * The Vertex Type describes the kind of simulation object a given SPFVertex
+ * represents.
+ *
+ * @see VertexType
+ * @returns The VertexType of the current SPFVertex object.
+ */
+  VertexType GetVertexType (void) const;
+
+/**
+ * @brief Set the Vertex Type field of a SPFVertex object.
+ * @internal
+ *
+ * The Vertex Type describes the kind of simulation object a given SPFVertex
+ * represents.
+ *
+ * @see VertexType
+ * @param type The new VertexType for the current SPFVertex object.
+ */
+  void SetVertexType (VertexType type);
+
+/**
+ * @brief Get the Vertex ID field of a SPFVertex object.
+ * @internal
+ *
+ * The Vertex ID uniquely identifies the simulation object a given SPFVertex
+ * represents.  Typically, this is the Router ID for SPFVertex objects 
+ * representing routers, and comes from the Link State Advertisement of a 
+ * router aggregated to a node in the simulation.  These IDs are allocated
+ * automatically by the routing environment and look like IP addresses 
+ * beginning at 0.0.0.0 and monotonically increasing as new routers are
+ * instantiated.
+ *
+ * @returns The Ipv4Address Vertex ID of the current SPFVertex object.
+ */
+  Ipv4Address GetVertexId (void) const;
+
+/**
+ * @brief Set the Vertex ID field of a SPFVertex object.
+ * @internal
+ *
+ * The Vertex ID uniquely identifies the simulation object a given SPFVertex
+ * represents.  Typically, this is the Router ID for SPFVertex objects 
+ * representing routers, and comes from the Link State Advertisement of a 
+ * router aggregated to a node in the simulation.  These IDs are allocated
+ * automatically by the routing environment and look like IP addresses 
+ * beginning at 0.0.0.0 and monotonically increase as new routers are
+ * instantiated.  This method is an explicit override of the automatically
+ * generated value.
+ *
+ * @param id The new Ipv4Address Vertex ID for the current SPFVertex object.
+ */
+  void SetVertexId (Ipv4Address id);
+
+/**
+ * @brief Get the Global Router Link State Advertisement returned by the 
+ * Global Router represented by this SPFVertex during the route discovery 
+ * process.
+ * @internal
+ *
+ * @see GlobalRouter
+ * @see GlobalRoutingLSA
+ * @see GlobalRouter::DiscoverLSAs ()
+ * @returns A pointer to the GlobalRoutingLSA found by the router represented
+ * by this SPFVertex object.
+ */
+  GlobalRoutingLSA* GetLSA (void) const;
+
+/**
+ * @brief Set the Global Router Link State Advertisement returned by the 
+ * Global Router represented by this SPFVertex during the route discovery 
+ * process.
+ * @internal
+ *
+ * @see SPFVertex::GetLSA ()
+ * @see GlobalRouter
+ * @see GlobalRoutingLSA
+ * @see GlobalRouter::DiscoverLSAs ()
+ * @warning Ownership of the LSA is transferred to the "this" SPFVertex.  You
+ * must not delete the LSA after calling this method.
+ * @param lsa A pointer to the GlobalRoutingLSA.
+ */
+  void SetLSA (GlobalRoutingLSA* lsa);
+
+/**
+ * @brief Get the distance from the root vertex to "this" SPFVertex object.
+ * @internal
+ *
+ * Each router in the simulation is associated with an SPFVertex object.  When
+ * calculating routes, each of these routers is, in turn, chosen as the "root"
+ * of the calculation and routes to all of the other routers are eventually
+ * saved in the routing tables of each of the chosen nodes.  Each of these 
+ * routers in the calculation has an associated SPFVertex.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set.  The "this" SPFVertex is the vertex to which
+ * a route is being calculated from the root.  The distance from the root that
+ * we're asking for is the number of hops from the root vertex to the vertex
+ * in question.
+ *
+ * The distance is calculated during route discovery and is stored in a
+ * member variable.  This method simply fetches that value.
+ *
+ * @returns The distance, in hops, from the root SPFVertex to "this" SPFVertex.
+ */
+  uint32_t GetDistanceFromRoot (void) const;
+
+/**
+ * @brief Set the distance from the root vertex to "this" SPFVertex object.
+ * @internal
+ *
+ * Each router in the simulation is associated with an SPFVertex object.  When
+ * calculating routes, each of these routers is, in turn, chosen as the "root"
+ * of the calculation and routes to all of the other routers are eventually
+ * saved in the routing tables of each of the chosen nodes.  Each of these 
+ * routers in the calculation has an associated SPFVertex.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set.  The "this" SPFVertex is the vertex to which
+ * a route is being calculated from the root.  The distance from the root that
+ * we're asking for is the number of hops from the root vertex to the vertex
+ * in question.
+ *
+ * @param distance The distance, in hops, from the root SPFVertex to "this"
+ * SPFVertex.
+ */
+  void SetDistanceFromRoot (uint32_t distance);
+
+/**
+ * @brief Get the interface ID that should be used to begin forwarding packets
+ * from the root SPFVertex to "this" SPFVertex.
+ * @internal
+ *
+ * Each router node in the simulation is associated with an SPFVertex object.
+ * When calculating routes, each of these routers is, in turn, chosen as the 
+ * "root" of the calculation and routes to all of the other routers are
+ * eventually saved in the routing tables of each of the chosen nodes.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set.  The "this" SPFVertex is the vertex that
+ * represents the host or network to which a route is being calculated from 
+ * the root.  The outgoing interface that we're asking for is the interface
+ * index on the root node that should be used to start packets along the
+ * path to "this" vertex.
+ *
+ * When initializing the root SPFVertex, the interface ID is determined by
+ * examining the Global Router Link Records of the Link State Advertisement
+ * generated by the root node's GlobalRouter.  These interfaces are used to 
+ * forward packets off of the root's network down those links.  As other 
+ * vertices are discovered which are further away from the root, they will 
+ * be accessible down one of the paths begun by a Global Router Link Record.
+ * 
+ * To forward packets to these hosts or networks, the root node must begin
+ * the forwarding process by sending the packets to the interface of that
+ * first hop.  This means that the first hop address and interface ID must
+ * be the same for all downstream SPFVertices.  We call this "inheriting"
+ * the interface and next hop.
+ *
+ * In this method, the root node is asking, "which of my local interfaces
+ * should I use to get a packet to the network or host represented by 'this'
+ * SPFVertex."
+ *
+ * @see GlobalRouter
+ * @see GlobalRoutingLSA
+ * @see GlobalRoutingLinkRecord
+ * @returns The interface index to use when forwarding packets to the host
+ * or network represented by "this" SPFVertex.
+ */
+  uint32_t GetOutgoingInterfaceId (void) const;
+
+/**
+ * @brief Set the interface ID that should be used to begin forwarding packets
+ * from the root SPFVertex to "this" SPFVertex.
+ * @internal
+ *
+ * Each router node in the simulation is associated with an SPFVertex object.
+ * When calculating routes, each of these routers is, in turn, chosen as the 
+ * "root" of the calculation and routes to all of the other routers are
+ * eventually saved in the routing tables of each of the chosen nodes.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set.  The "this" SPFVertex is the vertex that
+ * represents the host or network to which a route is being calculated from 
+ * the root.  The outgoing interface that we're asking for is the interface
+ * index on the root node that should be used to start packets along the
+ * path to "this" vertex.
+ *
+ * When initializing the root SPFVertex, the interface ID is determined by
+ * examining the Global Router Link Records of the Link State Advertisement
+ * generated by the root node's GlobalRouter.  These interfaces are used to 
+ * forward packets off of the root's network down those links.  As other 
+ * vertices are discovered which are further away from the root, they will 
+ * be accessible down one of the paths begun by a Global Router Link Record.
+ * 
+ * To forward packets to these hosts or networks, the root node must begin
+ * the forwarding process by sending the packets to the interface of that
+ * first hop.  This means that the first hop address and interface ID must
+ * be the same for all downstream SPFVertices.  We call this "inheriting"
+ * the interface and next hop.
+ *
+ * In this method, we are letting the root node know which of its local
+ * interfaces it should use to get a packet to the network or host represented
+ * by "this" SPFVertex.
+ *
+ * @see GlobalRouter
+ * @see GlobalRoutingLSA
+ * @see GlobalRoutingLinkRecord
+ * @param id The interface index to use when forwarding packets to the host or
+ * network represented by "this" SPFVertex.
+ */
+  void SetOutgoingInterfaceId (uint32_t id);
+
+/**
+ * @brief Get the IP address that should be used to begin forwarding packets 
+ * from the root SPFVertex to "this" SPFVertex.
+ * @internal
+ *
+ * Each router node in the simulation is associated with an SPFVertex object.
+ * When calculating routes, each of these routers is, in turn, chosen as the 
+ * "root" of the calculation and routes to all of the other routers are
+ * eventually saved in the routing tables of each of the chosen nodes.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set.  The "this" SPFVertex is the vertex that
+ * represents the host or network to which a route is being calculated from 
+ * the root.  The IP address that we're asking for is the address on the 
+ * remote side of a link off of the root node that should be used as the
+ * destination for packets along the path to "this" vertex.
+ *
+ * When initializing the root SPFVertex, the IP address used when forwarding
+ * packets is determined by examining the Global Router Link Records of the
+ * Link State Advertisement generated by the root node's GlobalRouter.  This
+ * address is used to forward packets off of the root's network down those
+ * links.  As other vertices / nodes are discovered which are further away
+ * from the root, they will be accessible down one of the paths via a link
+ * described by one of these Global Router Link Records.
+ * 
+ * To forward packets to these hosts or networks, the root node must begin
+ * the forwarding process by sending the packets to a first hop router down
+ * an interface.  This means that the first hop address and interface ID must
+ * be the same for all downstream SPFVertices.  We call this "inheriting"
+ * the interface and next hop.
+ *
+ * In this method, the root node is asking, "which router should I send a
+ * packet to in order to get that packet to the network or host represented 
+ * by 'this' SPFVertex."
+ *
+ * @see GlobalRouter
+ * @see GlobalRoutingLSA
+ * @see GlobalRoutingLinkRecord
+ * @returns The IP address to use when forwarding packets to the host
+ * or network represented by "this" SPFVertex.
+ */
+  Ipv4Address GetNextHop (void) const;
+
+/**
+ * @brief Set the IP address that should be used to begin forwarding packets 
+ * from the root SPFVertex to "this" SPFVertex.
+ * @internal
+ *
+ * Each router node in the simulation is associated with an SPFVertex object.
+ * When calculating routes, each of these routers is, in turn, chosen as the 
+ * "root" of the calculation and routes to all of the other routers are
+ * eventually saved in the routing tables of each of the chosen nodes.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set.  The "this" SPFVertex is the vertex that
+ * represents the host or network to which a route is being calculated from 
+ * the root.  The IP address that we're asking for is the address on the 
+ * remote side of a link off of the root node that should be used as the
+ * destination for packets along the path to "this" vertex.
+ *
+ * When initializing the root SPFVertex, the IP address used when forwarding
+ * packets is determined by examining the Global Router Link Records of the
+ * Link State Advertisement generated by the root node's GlobalRouter.  This
+ * address is used to forward packets off of the root's network down those
+ * links.  As other vertices / nodes are discovered which are further away
+ * from the root, they will be accessible down one of the paths via a link
+ * described by one of these Global Router Link Records.
+ * 
+ * To forward packets to these hosts or networks, the root node must begin
+ * the forwarding process by sending the packets to a first hop router down
+ * an interface.  This means that the first hop address and interface ID must
+ * be the same for all downstream SPFVertices.  We call this "inheriting"
+ * the interface and next hop.
+ *
+ * In this method we are telling the root node which router it should send
+ * should I send a packet to in order to get that packet to the network or
+ * host represented by 'this' SPFVertex."
+ *
+ * @see GlobalRouter
+ * @see GlobalRoutingLSA
+ * @see GlobalRoutingLinkRecord
+ * @param nextHop The IP address to use when forwarding packets to the host
+ * or network represented by "this" SPFVertex.
+ */
+  void SetNextHop (Ipv4Address nextHop);
+
+/**
+ * @brief Get a pointer to the SPFVector that is the parent of "this" 
+ * SPFVertex.
+ * @internal
+ *
+ * Each router node in the simulation is associated with an SPFVertex object.
+ * When calculating routes, each of these routers is, in turn, chosen as the 
+ * "root" of the calculation and routes to all of the other routers are
+ * eventually saved in the routing tables of each of the chosen nodes.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set and is the root of the SPF tree.
+ *
+ * This method returns a pointer to the parent node of "this" SPFVertex
+ * (both of which reside in that SPF tree).
+ *
+ * @returns A pointer to the SPFVertex that is the parent of "this" SPFVertex
+ * in the SPF tree.
+ */
+  SPFVertex* GetParent (void) const;
+
+/**
+ * @brief Set the pointer to the SPFVector that is the parent of "this" 
+ * SPFVertex.
+ * @internal
+ *
+ * Each router node in the simulation is associated with an SPFVertex object.
+ * When calculating routes, each of these routers is, in turn, chosen as the 
+ * "root" of the calculation and routes to all of the other routers are
+ * eventually saved in the routing tables of each of the chosen nodes.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set and is the root of the SPF tree.
+ *
+ * This method sets the parent pointer of "this" SPFVertex (both of which
+ * reside in that SPF tree).
+ *
+ * @param parent A pointer to the SPFVertex that is the parent of "this" 
+ * SPFVertex* in the SPF tree.
+ */
+  void SetParent (SPFVertex* parent);
+
+/**
+ * @brief Get the number of children of "this" SPFVertex.
+ * @internal
+ *
+ * Each router node in the simulation is associated with an SPFVertex object.
+ * When calculating routes, each of these routers is, in turn, chosen as the 
+ * "root" of the calculation and routes to all of the other routers are
+ * eventually saved in the routing tables of each of the chosen nodes.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set and is the root of the SPF tree.  Each vertex
+ * in the SPF tree can have a number of children that represent host or 
+ * network routes available via that vertex.
+ *
+ * This method returns the number of children of "this" SPFVertex (which 
+ * reside in the SPF tree).
+ *
+ * @returns The number of children of "this" SPFVertex (which reside in the
+ * SPF tree).
+ */
+  uint32_t GetNChildren (void) const;
+
+/**
+ * @brief Get a borrowed SPFVertex pointer to the specified child of "this" 
+ * SPFVertex.
+ * @internal
+ *
+ * Each router node in the simulation is associated with an SPFVertex object.
+ * When calculating routes, each of these routers is, in turn, chosen as the 
+ * "root" of the calculation and routes to all of the other routers are
+ * eventually saved in the routing tables of each of the chosen nodes.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set and is the root of the SPF tree.  Each vertex
+ * in the SPF tree can have a number of children that represent host or 
+ * network routes available via that vertex.
+ *
+ * This method the number of children of "this" SPFVertex (which reside in
+ * the SPF tree.
+ *
+ * @see SPFVertex::GetNChildren
+ * @param n The index (from 0 to the number of children minus 1) of the 
+ * child SPFVertex to return.
+ * @warning The pointer returned by GetChild () is a borrowed pointer.  You
+ * do not have any ownership of the underlying object and must not delete
+ * that object.
+ * @returns A pointer to the specified child SPFVertex (which resides in the
+ * SPF tree).
+ */
+  SPFVertex* GetChild (uint32_t n) const;
+
+/**
+ * @brief Get a borrowed SPFVertex pointer to the specified child of "this" 
+ * SPFVertex.
+ * @internal
+ *
+ * Each router node in the simulation is associated with an SPFVertex object.
+ * When calculating routes, each of these routers is, in turn, chosen as the 
+ * "root" of the calculation and routes to all of the other routers are
+ * eventually saved in the routing tables of each of the chosen nodes.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set and is the root of the SPF tree.  Each vertex
+ * in the SPF tree can have a number of children that represent host or 
+ * network routes available via that vertex.
+ *
+ * This method the number of children of "this" SPFVertex (which reside in
+ * the SPF tree.
+ *
+ * @see SPFVertex::GetNChildren
+ * @warning Ownership of the pointer added to the children of "this" 
+ * SPFVertex is transferred to the "this" SPFVertex.  You must not delete the
+ * (now) child SPFVertex after calling this method.
+ * @param child A pointer to the SPFVertex (which resides in the SPF tree) to
+ * be added to the list of children of "this" SPFVertex.
+ * @returns The number of children of "this" SPFVertex after the addition of
+ * the new child.
+ */
+  uint32_t AddChild (SPFVertex* child);
+
+private:
+  VertexType m_vertexType;
+  Ipv4Address m_vertexId;
+  GlobalRoutingLSA* m_lsa;
+  uint32_t m_distanceFromRoot;
+  uint32_t m_rootOif;
+  Ipv4Address m_nextHop;
+  SPFVertex* m_parent;
+  typedef std::list<SPFVertex*> ListOfSPFVertex_t;
+  ListOfSPFVertex_t m_children;
+
+/**
+ * @brief The SPFVertex copy construction is disallowed.  There's no need for
+ * it and a compiler provided shallow copy would be wrong.
+ */
+  SPFVertex (SPFVertex& v);
+
+/**
+ * @brief The SPFVertex copy assignment operator is disallowed.  There's no 
+ * need for it and a compiler provided shallow copy would be wrong.
+ */
+  SPFVertex& operator= (SPFVertex& v);
+};
+
+/**
+ * @brief The Link State DataBase (LSDB) of the Global Route Manager.
+ *
+ * Each node in the simulation participating in global routing has a
+ * GlobalRouter interface.  The primary job of this interface is to export
+ * Global Router Link State Advertisements (LSAs).  These advertisements in
+ * turn contain a number of Global Router Link Records that describe the 
+ * point to point links from the underlying node to other nodes (that will 
+ * also export their own LSAs.
+ *
+ * This class implements a searchable database of LSAs gathered from every
+ * router in the simulation.
+ */
+class GlobalRouteManagerLSDB
+{
+public:
+/**
+ * @brief Construct an empty Global Router Manager Link State Database.
+ * @internal
+ *
+ * The database map composing the Link State Database is initialized in
+ * this constructor.
+ */
+  GlobalRouteManagerLSDB ();
+
+/**
+ * @brief Destroy an empty Global Router Manager Link State Database.
+ * @internal
+ *
+ * The database map is walked and all of the Link State Advertisements stored
+ * in the database are freed; then the database map itself is clear ()ed to
+ * release any remaining resources.
+ */
+  ~GlobalRouteManagerLSDB ();
+
+/**
+ * @brief Insert an IP address / Link State Advertisement pair into the Link
+ * State Database.
+ * @internal
+ *
+ * The IPV4 address and the GlobalRoutingLSA given as parameters are converted
+ * to an STL pair and are inserted into the database map.
+ *
+ * @see GlobalRoutingLSA
+ * @see Ipv4Address
+ * @param addr The IP address associated with the LSA.  Typically the Router 
+ * ID.
+ * @param lsa A pointer to the Link State Advertisement for the router.
+ */
+  void Insert(Ipv4Address addr, GlobalRoutingLSA* lsa);
+
+/**
+ * @brief Look up the Link State Advertisement associated with the given
+ * link state ID (address).
+ * @internal
+ *
+ * The database map is searched for the given IPV4 address and corresponding
+ * GlobalRoutingLSA is returned.
+ *
+ * @see GlobalRoutingLSA
+ * @see Ipv4Address
+ * @param addr The IP address associated with the LSA.  Typically the Router 
+ * ID.
+ * @returns A pointer to the Link State Advertisement for the router specified
+ * by the IP address addr.
+ */
+  GlobalRoutingLSA* GetLSA (Ipv4Address addr) const;
+/**
+ * @brief Look up the Link State Advertisement associated with the given
+ * link state ID (address).  This is a variation of the GetLSA call
+ * to allow the LSA to be found by matching addr with the LinkData field
+ * of the TransitNetwork link record.
+ * @internal
+ *
+ * @see GetLSA
+ * @param addr The IP address associated with the LSA.  Typically the Router 
+ * @returns A pointer to the Link State Advertisement for the router specified
+ * by the IP address addr.
+ * ID.
+ */
+  GlobalRoutingLSA* GetLSAByLinkData (Ipv4Address addr) const;
+
+/**
+ * @brief Set all LSA flags to an initialized state, for SPF computation
+ * @internal
+ *
+ * This function walks the database and resets the status flags of all of the
+ * contained Link State Advertisements to LSA_SPF_NOT_EXPLORED.  This is done
+ * prior to each SPF calculation to reset the state of the SPFVertex structures
+ * that will reference the LSAs during the calculation.
+ *
+ * @see GlobalRoutingLSA
+ * @see SPFVertex
+ */
+  void Initialize ();
+
+private:
+  typedef std::map<Ipv4Address, GlobalRoutingLSA*> LSDBMap_t;
+  typedef std::pair<Ipv4Address, GlobalRoutingLSA*> LSDBPair_t;
+
+  LSDBMap_t m_database;
+/**
+ * @brief GlobalRouteManagerLSDB copy construction is disallowed.  There's no 
+ * need for it and a compiler provided shallow copy would be wrong.
+ */
+  GlobalRouteManagerLSDB (GlobalRouteManagerLSDB& lsdb);
+
+/**
+ * @brief The SPFVertex copy assignment operator is disallowed.  There's no 
+ * need for it and a compiler provided shallow copy would be wrong.
+ */
+  GlobalRouteManagerLSDB& operator= (GlobalRouteManagerLSDB& lsdb);
+};
+
+/**
+ * @brief A global router implementation.
+ *
+ * This singleton object can query interface each node in the system
+ * for a GlobalRouter interface.  For those nodes, it fetches one or
+ * more Link State Advertisements and stores them in a local database.
+ * Then, it can compute shortest paths on a per-node basis to all routers, 
+ * and finally configure each of the node's forwarding tables.
+ *
+ * The design is guided by OSPFv2 RFC 2328 section 16.1.1 and quagga ospfd.
+ */
+class GlobalRouteManagerImpl
+{
+public:
+  GlobalRouteManagerImpl ();
+  virtual ~GlobalRouteManagerImpl ();
+/**
+ * @brief Select which nodes in the system are to be router nodes and 
+ * aggregate the appropriate interfaces onto those nodes.
+ * @internal
+ *
+ */
+  virtual void SelectRouterNodes ();
+
+/**
+ * @brief Build the routing database by gathering Link State Advertisements
+ * from each node exporting a GlobalRouter interface.
+ * @internal
+ */
+  virtual void BuildGlobalRoutingDatabase ();
+
+/**
+ * @brief Compute routes using a Dijkstra SPF computation and populate
+ * per-node forwarding tables
+ * @internal
+ */
+  virtual void InitializeRoutes ();
+
+/**
+ * @brief Debugging routine; allow client code to supply a pre-built LSDB
+ * @internal
+ */
+  void DebugUseLsdb (GlobalRouteManagerLSDB*);
+
+/**
+ * @brief Debugging routine; call the core SPF from the unit tests
+ * @internal
+ */
+  void DebugSPFCalculate (Ipv4Address root);
+
+private:
+/**
+ * @brief GlobalRouteManagerImpl copy construction is disallowed.
+ * There's no  need for it and a compiler provided shallow copy would be 
+ * wrong.
+ */
+  GlobalRouteManagerImpl (GlobalRouteManagerImpl& srmi);
+
+/**
+ * @brief Global Route Manager Implementation assignment operator is
+ * disallowed.  There's no  need for it and a compiler provided shallow copy
+ * would be hopelessly wrong.
+ */
+  GlobalRouteManagerImpl& operator= (GlobalRouteManagerImpl& srmi);
+
+  SPFVertex* m_spfroot;
+  GlobalRouteManagerLSDB* m_lsdb;
+  void SPFCalculate (Ipv4Address root);
+  void SPFNext (SPFVertex*, CandidateQueue&);
+  int SPFNexthopCalculation (SPFVertex* v, SPFVertex* w, 
+    GlobalRoutingLinkRecord* l, uint32_t distance);
+  void SPFVertexAddParent (SPFVertex* v);
+  GlobalRoutingLinkRecord* SPFGetNextLink (SPFVertex* v, SPFVertex* w, 
+    GlobalRoutingLinkRecord* prev_link);
+  void SPFIntraAddRouter (SPFVertex* v);
+  void SPFIntraAddTransit (SPFVertex* v);
+  uint32_t FindOutgoingInterfaceId (Ipv4Address a, 
+    Ipv4Mask amask = Ipv4Mask("255.255.255.255"));
+};
+
+} // namespace ns3
+
+#endif /* GLOBAL_ROUTE_MANAGER_IMPL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/routing/global-routing/global-route-manager.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,72 @@
+/* -*- 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/assert.h"
+#include "ns3/log.h"
+#include "ns3/simulation-singleton.h"
+#include "global-route-manager.h"
+#include "global-route-manager-impl.h"
+
+namespace ns3 {
+
+// ---------------------------------------------------------------------------
+//
+// GlobalRouteManager Implementation
+//
+// ---------------------------------------------------------------------------
+
+  void
+GlobalRouteManager::PopulateRoutingTables () 
+{
+  SelectRouterNodes ();
+  BuildGlobalRoutingDatabase ();
+  InitializeRoutes ();
+}
+
+  void
+GlobalRouteManager::SelectRouterNodes () 
+{
+  SimulationSingleton<GlobalRouteManagerImpl>::Get ()->
+    SelectRouterNodes ();
+}
+
+  void
+GlobalRouteManager::BuildGlobalRoutingDatabase () 
+{
+  SimulationSingleton<GlobalRouteManagerImpl>::Get ()->
+    BuildGlobalRoutingDatabase ();
+}
+
+  void
+GlobalRouteManager::InitializeRoutes ()
+{
+  SimulationSingleton<GlobalRouteManagerImpl>::Get ()->
+    InitializeRoutes ();
+}
+
+  uint32_t
+GlobalRouteManager::AllocateRouterId ()
+{
+  static uint32_t routerId = 0;
+  return routerId++;
+}
+
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/routing/global-routing/global-route-manager.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,98 @@
+/* -*- 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
+ *
+ * Authors:  Craig Dowell (craigdo@ee.washington.edu)
+ *           Tom Henderson (tomhend@u.washington.edu)
+ */
+
+#ifndef GLOBAL_ROUTE_MANAGER_H
+#define GLOBAL_ROUTE_MANAGER_H
+
+namespace ns3 {
+
+/**
+ * @brief A global global router
+ *
+ * This singleton object can query interface each node in the system
+ * for a GlobalRouter interface.  For those nodes, it fetches one or
+ * more Link State Advertisements and stores them in a local database.
+ * Then, it can compute shortest paths on a per-node basis to all routers, 
+ * and finally configure each of the node's forwarding tables.
+ *
+ * The design is guided by OSPFv2 RFC 2328 section 16.1.1 and quagga ospfd.
+ */
+class GlobalRouteManager
+{
+public:
+/**
+ * @brief Build a routing database and initialize the routing tables of
+ * the nodes in the simulation.
+ *
+ * All this function does is call  BuildGlobalRoutingDatabase () and
+ * InitializeRoutes ().
+ *
+ * @see BuildGlobalRoutingDatabase ();
+ * @see InitializeRoutes ();
+ */
+  static void PopulateRoutingTables ();
+
+/**
+ * @brief Allocate a 32-bit router ID from monotonically increasing counter.
+ */
+  static uint32_t AllocateRouterId ();
+
+private:
+/**
+ * @brief Select which nodes in the system are to be router nodes and 
+ * aggregate the appropriate interfaces onto those nodes.
+ * @internal
+ *
+ */
+  static void SelectRouterNodes ();
+
+/**
+ * @brief Build the routing database by gathering Link State Advertisements
+ * from each node exporting a GlobalRouter interface.
+ * @internal
+ *
+ */
+  static void BuildGlobalRoutingDatabase ();
+
+/**
+ * @brief Compute routes using a Dijkstra SPF computation and populate
+ * per-node forwarding tables
+ * @internal
+ */
+  static void InitializeRoutes ();
+
+/**
+ * @brief Global Route Manager copy construction is disallowed.  There's no 
+ * need for it and a compiler provided shallow copy would be wrong.
+ *
+ */
+  GlobalRouteManager (GlobalRouteManager& srm);
+
+/**
+ * @brief Global Router copy assignment operator is disallowed.  There's no 
+ * need for it and a compiler provided shallow copy would be wrong.
+ */
+  GlobalRouteManager& operator= (GlobalRouteManager& srm);
+};
+
+} // namespace ns3
+
+#endif /* GLOBAL_ROUTE_MANAGER_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/routing/global-routing/global-router-interface.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,851 @@
+/* -*- 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
+ *
+ * Authors:  Tom Henderson (tomhend@u.washington.edu)
+ */
+
+#include "ns3/log.h"
+#include "ns3/assert.h"
+#include "ns3/channel.h"
+#include "ns3/net-device.h"
+#include "ns3/internet-node.h"
+#include "ns3/ipv4.h"
+#include "global-router-interface.h"
+
+NS_LOG_COMPONENT_DEFINE ("GlobalRouter");
+
+namespace ns3 {
+
+// ---------------------------------------------------------------------------
+//
+// GlobalRoutingLinkRecord Implementation
+//
+// ---------------------------------------------------------------------------
+
+GlobalRoutingLinkRecord::GlobalRoutingLinkRecord ()
+:
+  m_linkId ("0.0.0.0"),
+  m_linkData ("0.0.0.0"),
+  m_linkType (Unknown),
+  m_metric (0)
+{
+  NS_LOG_FUNCTION;
+}
+
+GlobalRoutingLinkRecord::GlobalRoutingLinkRecord (
+  LinkType    linkType, 
+  Ipv4Address linkId, 
+  Ipv4Address linkData, 
+  uint32_t    metric)
+:
+  m_linkId (linkId),
+  m_linkData (linkData),
+  m_linkType (linkType),
+  m_metric (metric)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << linkType << ", " << linkId << ", " << linkData << 
+    ", " << metric << ")");
+}
+
+GlobalRoutingLinkRecord::~GlobalRoutingLinkRecord ()
+{
+  NS_LOG_FUNCTION;
+}
+
+  Ipv4Address
+GlobalRoutingLinkRecord::GetLinkId (void) const
+{
+  NS_LOG_FUNCTION;
+  return m_linkId;
+}
+
+  void
+GlobalRoutingLinkRecord::SetLinkId (Ipv4Address addr)
+{
+  NS_LOG_FUNCTION;
+  m_linkId = addr;
+}
+
+  Ipv4Address
+GlobalRoutingLinkRecord::GetLinkData (void) const
+{
+  NS_LOG_FUNCTION;
+  return m_linkData;
+}
+
+  void
+GlobalRoutingLinkRecord::SetLinkData (Ipv4Address addr)
+{
+  NS_LOG_FUNCTION;
+  m_linkData = addr;
+}
+
+  GlobalRoutingLinkRecord::LinkType
+GlobalRoutingLinkRecord::GetLinkType (void) const
+{
+  NS_LOG_FUNCTION;
+  return m_linkType;
+}
+
+  void
+GlobalRoutingLinkRecord::SetLinkType (
+  GlobalRoutingLinkRecord::LinkType linkType)
+{
+  NS_LOG_FUNCTION;
+  m_linkType = linkType;
+}
+
+  uint32_t
+GlobalRoutingLinkRecord::GetMetric (void) const
+{
+  NS_LOG_FUNCTION;
+  return m_metric;
+}
+
+  void
+GlobalRoutingLinkRecord::SetMetric (uint32_t metric)
+{
+  NS_LOG_FUNCTION;
+  m_metric = metric;
+}
+
+// ---------------------------------------------------------------------------
+//
+// GlobalRoutingLSA Implementation
+//
+// ---------------------------------------------------------------------------
+
+GlobalRoutingLSA::GlobalRoutingLSA()
+  : 
+  m_lsType (GlobalRoutingLSA::Unknown),
+  m_linkStateId("0.0.0.0"),
+  m_advertisingRtr("0.0.0.0"),
+  m_linkRecords(),
+  m_networkLSANetworkMask("0.0.0.0"),
+  m_attachedRouters(),
+  m_status(GlobalRoutingLSA::LSA_SPF_NOT_EXPLORED)
+{
+  NS_LOG_FUNCTION;
+}
+
+GlobalRoutingLSA::GlobalRoutingLSA (
+  GlobalRoutingLSA::SPFStatus status,
+  Ipv4Address linkStateId, 
+  Ipv4Address advertisingRtr)
+:
+  m_lsType (GlobalRoutingLSA::Unknown),
+  m_linkStateId(linkStateId),
+  m_advertisingRtr(advertisingRtr),
+  m_linkRecords(),
+  m_networkLSANetworkMask("0.0.0.0"),
+  m_attachedRouters(),
+  m_status(status)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_PARAM ("(" << status << ", " << linkStateId << ", " << 
+    advertisingRtr << ")");
+}
+
+GlobalRoutingLSA::GlobalRoutingLSA (GlobalRoutingLSA& lsa)
+  : m_lsType(lsa.m_lsType), m_linkStateId(lsa.m_linkStateId), 
+    m_advertisingRtr(lsa.m_advertisingRtr), 
+    m_networkLSANetworkMask(lsa.m_networkLSANetworkMask), 
+    m_status(lsa.m_status)
+{
+  NS_LOG_FUNCTION;
+  NS_ASSERT_MSG(IsEmpty(), 
+    "GlobalRoutingLSA::GlobalRoutingLSA (): Non-empty LSA in constructor");
+  CopyLinkRecords (lsa);
+}
+
+  GlobalRoutingLSA&
+GlobalRoutingLSA::operator= (const GlobalRoutingLSA& lsa)
+{
+  NS_LOG_FUNCTION;
+  m_lsType = lsa.m_lsType;
+  m_linkStateId = lsa.m_linkStateId;
+  m_advertisingRtr = lsa.m_advertisingRtr;
+  m_networkLSANetworkMask = lsa.m_networkLSANetworkMask, 
+  m_status = lsa.m_status;
+
+  ClearLinkRecords ();
+  CopyLinkRecords (lsa);
+  return *this;
+}
+
+  void
+GlobalRoutingLSA::CopyLinkRecords (const GlobalRoutingLSA& lsa)
+{
+  NS_LOG_FUNCTION;
+  for (ListOfLinkRecords_t::const_iterator i = lsa.m_linkRecords.begin ();
+       i != lsa.m_linkRecords.end (); 
+       i++)
+    {
+      GlobalRoutingLinkRecord *pSrc = *i;
+      GlobalRoutingLinkRecord *pDst = new GlobalRoutingLinkRecord;
+
+      pDst->SetLinkType (pSrc->GetLinkType ());
+      pDst->SetLinkId (pSrc->GetLinkId ());
+      pDst->SetLinkData (pSrc->GetLinkData ());
+
+      m_linkRecords.push_back(pDst);
+      pDst = 0;
+    }
+
+   m_attachedRouters = lsa.m_attachedRouters;
+}
+
+GlobalRoutingLSA::~GlobalRoutingLSA()
+{
+  NS_LOG_FUNCTION;
+  ClearLinkRecords ();
+}
+
+  void
+GlobalRoutingLSA::ClearLinkRecords(void)
+{
+  NS_LOG_FUNCTION;
+  for ( ListOfLinkRecords_t::iterator i = m_linkRecords.begin ();
+        i != m_linkRecords.end (); 
+        i++)
+    {
+      NS_LOG_LOGIC ("Free link record");
+
+      GlobalRoutingLinkRecord *p = *i;
+      delete p;
+      p = 0;
+
+      *i = 0;
+    }
+  NS_LOG_LOGIC ("Clear list");
+  m_linkRecords.clear();
+}
+
+  uint32_t
+GlobalRoutingLSA::AddLinkRecord (GlobalRoutingLinkRecord* lr)
+{
+  NS_LOG_FUNCTION;
+  m_linkRecords.push_back (lr);
+  return m_linkRecords.size ();
+}
+
+  uint32_t
+GlobalRoutingLSA::GetNLinkRecords (void) const
+{
+  NS_LOG_FUNCTION;
+  return m_linkRecords.size ();
+}
+
+  GlobalRoutingLinkRecord *
+GlobalRoutingLSA::GetLinkRecord (uint32_t n) const
+{
+  NS_LOG_FUNCTION;
+  uint32_t j = 0;
+  for ( ListOfLinkRecords_t::const_iterator i = m_linkRecords.begin ();
+        i != m_linkRecords.end (); 
+        i++, j++)
+    {
+      if (j == n) 
+        {
+          return *i;
+        }
+    }
+  NS_ASSERT_MSG(false, "GlobalRoutingLSA::GetLinkRecord (): invalid index");
+  return 0;
+}
+
+  bool
+GlobalRoutingLSA::IsEmpty (void) const
+{
+  NS_LOG_FUNCTION;
+  return m_linkRecords.size () == 0;
+}
+
+  GlobalRoutingLSA::LSType
+GlobalRoutingLSA::GetLSType (void) const
+{
+  NS_LOG_FUNCTION;
+  return m_lsType;
+}
+
+  void 
+GlobalRoutingLSA::SetLSType (GlobalRoutingLSA::LSType typ) 
+{
+  NS_LOG_FUNCTION;
+  m_lsType = typ;
+}
+
+  Ipv4Address
+GlobalRoutingLSA::GetLinkStateId (void) const
+{
+  NS_LOG_FUNCTION;
+  return m_linkStateId;
+}
+
+  void
+GlobalRoutingLSA::SetLinkStateId (Ipv4Address addr)
+{
+  NS_LOG_FUNCTION;
+  m_linkStateId = addr;
+}
+
+  Ipv4Address
+GlobalRoutingLSA::GetAdvertisingRouter (void) const
+{
+  NS_LOG_FUNCTION;
+  return m_advertisingRtr;
+}
+
+  void
+GlobalRoutingLSA::SetAdvertisingRouter (Ipv4Address addr)
+{
+  NS_LOG_FUNCTION;
+  m_advertisingRtr = addr;
+}
+
+  void 
+GlobalRoutingLSA::SetNetworkLSANetworkMask (Ipv4Mask mask)
+{
+  NS_LOG_FUNCTION;
+  m_networkLSANetworkMask = mask;
+}
+
+  Ipv4Mask 
+GlobalRoutingLSA::GetNetworkLSANetworkMask (void) const
+{
+  NS_LOG_FUNCTION;
+  return m_networkLSANetworkMask;
+}
+
+  GlobalRoutingLSA::SPFStatus
+GlobalRoutingLSA::GetStatus (void) const
+{
+  NS_LOG_FUNCTION;
+  return m_status;
+}
+
+  uint32_t 
+GlobalRoutingLSA::AddAttachedRouter (Ipv4Address addr)
+{
+  NS_LOG_FUNCTION;
+  m_attachedRouters.push_back (addr);
+  return m_attachedRouters.size ();
+}
+
+  uint32_t 
+GlobalRoutingLSA::GetNAttachedRouters (void) const
+{
+  NS_LOG_FUNCTION;
+  return m_attachedRouters.size (); 
+}
+
+  Ipv4Address 
+GlobalRoutingLSA::GetAttachedRouter (uint32_t n) const
+{
+  NS_LOG_FUNCTION;
+  uint32_t j = 0;
+  for ( ListOfAttachedRouters_t::const_iterator i = m_attachedRouters.begin ();
+        i != m_attachedRouters.end (); 
+        i++, j++)
+    {
+      if (j == n) 
+        {
+          return *i;
+        }
+    }
+  NS_ASSERT_MSG(false, 
+    "GlobalRoutingLSA::GetAttachedRouter (): invalid index");
+  return Ipv4Address("0.0.0.0");
+}
+
+  void
+GlobalRoutingLSA::SetStatus (GlobalRoutingLSA::SPFStatus status)
+{
+  NS_LOG_FUNCTION;
+  m_status = status;
+}
+
+  void 
+GlobalRoutingLSA::Print (std::ostream &os) const
+{
+  os << "m_lsType = " << m_lsType << std::endl <<
+        "m_linkStateId = " << m_linkStateId << std::endl <<
+        "m_advertisingRtr = " << m_advertisingRtr << std::endl;
+
+  if (m_lsType == GlobalRoutingLSA::RouterLSA) 
+    {
+      for ( ListOfLinkRecords_t::const_iterator i = m_linkRecords.begin ();
+            i != m_linkRecords.end (); 
+            i++)
+        {
+          GlobalRoutingLinkRecord *p = *i;
+          os << "----------" << std::endl;
+          os << "m_linkId = " << p->GetLinkId () << std::endl;
+          os << "m_linkData = " << p->GetLinkData () << std::endl;
+        }
+    }
+  else if (m_lsType == GlobalRoutingLSA::NetworkLSA) 
+    {
+      os << "----------" << std::endl;
+      os << "m_networkLSANetworkMask = " << m_networkLSANetworkMask 
+         << std::endl;
+      for ( ListOfAttachedRouters_t::const_iterator i = 
+            m_attachedRouters.begin ();
+            i != m_attachedRouters.end (); 
+            i++)
+        {
+          Ipv4Address p = *i;
+          os << "attachedRouter = " << p << std::endl;
+        }
+    }
+  else 
+    {
+      NS_ASSERT_MSG(0, "Illegal LSA LSType: " << m_lsType);
+    }
+}
+
+std::ostream& operator<< (std::ostream& os, GlobalRoutingLSA& lsa)
+{
+  lsa.Print (os);
+  return os;
+}
+
+// ---------------------------------------------------------------------------
+//
+// GlobalRouter Implementation
+//
+// ---------------------------------------------------------------------------
+
+const InterfaceId GlobalRouter::iid = 
+  MakeInterfaceId ("GlobalRouter", Object::iid);
+
+GlobalRouter::GlobalRouter (Ptr<Node> node)
+  : m_node(node), m_LSAs()
+{
+  NS_LOG_FUNCTION;
+  SetInterfaceId (GlobalRouter::iid);
+  m_routerId.Set(GlobalRouteManager::AllocateRouterId ());
+}
+
+GlobalRouter::~GlobalRouter ()
+{
+  NS_LOG_FUNCTION;
+  ClearLSAs();
+}
+
+void
+GlobalRouter::DoDispose ()
+{
+  NS_LOG_FUNCTION;
+  m_node = 0;
+  Object::DoDispose ();
+}
+
+  void
+GlobalRouter::ClearLSAs ()
+{
+  NS_LOG_FUNCTION;
+  for ( ListOfLSAs_t::iterator i = m_LSAs.begin ();
+        i != m_LSAs.end (); 
+        i++)
+    {
+      NS_LOG_LOGIC ("Free LSA");
+
+      GlobalRoutingLSA *p = *i;
+      delete p;
+      p = 0;
+
+      *i = 0;
+    }
+  NS_LOG_LOGIC ("Clear list");
+  m_LSAs.clear();
+}
+
+  Ipv4Address
+GlobalRouter::GetRouterId (void) const
+{
+  NS_LOG_FUNCTION;
+  return m_routerId;
+}
+
+//
+// Go out and discover any adjacent routers and build the Link State 
+// Advertisements that reflect them and their associated networks.
+// 
+  uint32_t 
+GlobalRouter::DiscoverLSAs (void)
+{
+  NS_LOG_FUNCTION;
+  NS_LOG_LOGIC("For node " << m_node->GetId () );
+  NS_ASSERT_MSG(m_node, 
+    "GlobalRouter::DiscoverLSAs (): <Node> interface not set");
+
+  ClearLSAs ();
+
+// While building the router-LSA, keep a list of those NetDevices for
+// which I am the designated router and need to later build a NetworkLSA
+  std::list<Ptr<NetDevice> > listOfDRInterfaces;
+
+//
+// We're aggregated to a node.  We need to ask the node for a pointer to its
+// Ipv4 interface.  This is where the information regarding the attached 
+// interfaces lives.
+//
+  Ptr<Ipv4> ipv4Local = m_node->QueryInterface<Ipv4> (Ipv4::iid);
+  NS_ASSERT_MSG(ipv4Local, 
+    "GlobalRouter::DiscoverLSAs (): QI for <Ipv4> interface failed");
+//
+// Each node originates a Router-LSA
+//
+  GlobalRoutingLSA *pLSA = new GlobalRoutingLSA;
+  pLSA->SetLSType (GlobalRoutingLSA::RouterLSA);
+  pLSA->SetLinkStateId (m_routerId);
+  pLSA->SetAdvertisingRouter (m_routerId);
+  pLSA->SetStatus (GlobalRoutingLSA::LSA_SPF_NOT_EXPLORED);
+//
+// We need to ask the node for the number of net devices attached. This isn't
+// necessarily equal to the number of links to adjacent nodes (other routers)
+// as the number of devices may include those for stub networks (e.g., 
+// ethernets, etc.).  
+//
+  uint32_t numDevices = m_node->GetNDevices();
+  NS_LOG_LOGIC ("numDevices = " << numDevices);
+  for (uint32_t i = 0; i < numDevices; ++i)
+    {
+      Ptr<NetDevice> ndLocal = m_node->GetDevice(i);
+
+      if (ndLocal->IsBroadcast () && !ndLocal->IsPointToPoint () )
+        {
+          NS_LOG_LOGIC ("Broadcast link");
+          GlobalRoutingLinkRecord *plr = new GlobalRoutingLinkRecord;
+//
+// We need to determine whether we are on a transit or stub network
+// If we find at least one more router on this channel, we are a transit
+//
+//
+// Now, we have to find the Ipv4 interface whose netdevice is the one we 
+// just found.  This is still the IP on the local side of the channel.  There 
+// is a function to do this used down in the guts of the stack, but it's not 
+// exported so we had to whip up an equivalent.
+//
+          uint32_t ifIndexLocal = FindIfIndexForDevice(m_node, ndLocal);
+          Ipv4Address addrLocal = ipv4Local->GetAddress(ifIndexLocal);
+          Ipv4Mask maskLocal = ipv4Local->GetNetworkMask(ifIndexLocal);
+          NS_LOG_LOGIC ("Working with local address " << addrLocal);
+//
+// Now, we're going to walk over to the remote net device on the other end of 
+// the point-to-point channel we now know we have.  This is where our adjacent 
+// router (to use OSPF lingo) is running.  
+//
+          Ptr<Channel> ch = ndLocal->GetChannel();
+          uint32_t nDevices = ch->GetNDevices();
+          if (nDevices == 1)
+            {
+              // This is a stub broadcast interface
+              NS_LOG_LOGIC("Router-LSA stub broadcast link");
+              // XXX in future, need to consider if >1 includes other routers
+              plr->SetLinkType (GlobalRoutingLinkRecord::StubNetwork);
+              // Link ID is IP network number of attached network
+              plr->SetLinkId (addrLocal.CombineMask(maskLocal));
+              // Link Data is network mask; convert to Ipv4Address
+              Ipv4Address maskLocalAddr;
+              maskLocalAddr.Set(maskLocal.GetHostOrder ());
+              plr->SetLinkData (maskLocalAddr);
+              // Cost is interface's configured output cost (NOTYET)
+              plr->SetMetric (1);
+              pLSA->AddLinkRecord(plr);
+              plr = 0;
+              continue;
+            }
+          else
+            {
+              NS_LOG_LOGIC ("Router-LSA Broadcast link");
+              // multiple routers on a broadcast interface
+              // lowest IP address is designated router
+              plr->SetLinkType (GlobalRoutingLinkRecord::TransitNetwork);
+              // Link ID is IP interface address of designated router
+              Ipv4Address desigRtr = 
+                FindDesignatedRouterForLink (m_node, ndLocal);
+              if (desigRtr == addrLocal) 
+                {
+                  listOfDRInterfaces.push_back (ndLocal);
+                  NS_LOG_LOGIC (m_node->GetId () << " is a DR");
+                }
+              plr->SetLinkId (desigRtr);
+              // Link Data is router's own IP address
+              plr->SetLinkData (addrLocal);
+              // Cost is interface's configured output cost (NOTYET)
+              plr->SetMetric (1);
+              pLSA->AddLinkRecord (plr);
+              plr = 0;
+              continue;
+            }
+        }
+      else if (ndLocal->IsPointToPoint () )
+        {
+          NS_LOG_LOGIC ("Router-LSA Point-to-point device");
+//
+// Now, we have to find the Ipv4 interface whose netdevice is the one we 
+// just found.  This is still the IP on the local side of the channel.  There 
+// is a function to do this used down in the guts of the stack, but it's not 
+// exported so we had to whip up an equivalent.
+//
+          uint32_t ifIndexLocal = FindIfIndexForDevice(m_node, ndLocal);
+//
+// Now that we have the Ipv4 interface index, we can get the address and mask
+// we need.
+//
+          Ipv4Address addrLocal = ipv4Local->GetAddress(ifIndexLocal);
+          Ipv4Mask maskLocal = ipv4Local->GetNetworkMask(ifIndexLocal);
+          NS_LOG_LOGIC ("Working with local address " << addrLocal);
+//
+// Now, we're going to walk over to the remote net device on the other end of 
+// the point-to-point channel we now know we have.  This is where our adjacent 
+// router (to use OSPF lingo) is running.  
+//
+          Ptr<Channel> ch = ndLocal->GetChannel();
+          Ptr<NetDevice> ndRemote = GetAdjacent(ndLocal, ch);
+//
+// The adjacent net device is aggregated to a node.  We need to ask that net 
+// device for its node, then ask that node for its Ipv4 interface.
+//
+          Ptr<Node> nodeRemote = ndRemote->GetNode();
+          Ptr<Ipv4> ipv4Remote = nodeRemote->QueryInterface<Ipv4> (Ipv4::iid);
+          NS_ASSERT_MSG(ipv4Remote, 
+            "GlobalRouter::DiscoverLSAs (): QI for remote <Ipv4> failed");
+//
+// Per the OSPF spec, we're going to need the remote router ID, so we might as
+// well get it now.
+//
+          Ptr<GlobalRouter> srRemote = 
+            nodeRemote->QueryInterface<GlobalRouter> (GlobalRouter::iid);
+          NS_ASSERT_MSG(srRemote, 
+            "GlobalRouter::DiscoverLSAs():QI for remote <GlobalRouter> failed");
+          Ipv4Address rtrIdRemote = srRemote->GetRouterId();
+          NS_LOG_LOGIC ("Working with remote router " << rtrIdRemote);
+//
+// Now, just like we did above, we need to get the IP interface index for the 
+// net device on the other end of the point-to-point channel.
+//
+          uint32_t ifIndexRemote = FindIfIndexForDevice(nodeRemote, ndRemote);
+//
+// Now that we have the Ipv4 interface, we can get the (remote) address and
+// mask we need.
+//
+          Ipv4Address addrRemote = ipv4Remote->GetAddress(ifIndexRemote);
+          Ipv4Mask maskRemote = ipv4Remote->GetNetworkMask(ifIndexRemote);
+          NS_LOG_LOGIC ("Working with remote address " << addrRemote);
+//
+// Now we can fill out the link records for this link.  There are always two
+// link records; the first is a point-to-point record describing the link and
+// the second is a stub network record with the network number.
+//
+          GlobalRoutingLinkRecord *plr = new GlobalRoutingLinkRecord;
+          plr->SetLinkType (GlobalRoutingLinkRecord::PointToPoint);
+          plr->SetLinkId (rtrIdRemote);
+          plr->SetLinkData (addrLocal);
+          pLSA->AddLinkRecord (plr);
+          plr = 0;
+
+          plr = new GlobalRoutingLinkRecord;
+          plr->SetLinkType (GlobalRoutingLinkRecord::StubNetwork);
+          plr->SetLinkId (addrRemote);
+          plr->SetLinkData (Ipv4Address(maskRemote.GetHostOrder()));  // Frown
+          pLSA->AddLinkRecord (plr);
+          plr = 0;
+        }
+      else
+        {
+          NS_ASSERT_MSG(0, "GlobalRouter::DiscoverLSAs (): unknown link type");
+        }
+
+    }
+//
+// The LSA goes on a list of LSAs in case we want to begin exporting other
+// kinds of advertisements (than Router LSAs).
+  m_LSAs.push_back (pLSA);
+  NS_LOG_LOGIC (*pLSA);
+
+// Now, determine whether we need to build a NetworkLSA
+  if (listOfDRInterfaces.size () > 0)
+    {
+      for (std::list<Ptr<NetDevice> >::iterator i = listOfDRInterfaces.begin ();
+        i != listOfDRInterfaces.end (); i++)
+        {
+// Build one NetworkLSA for each interface that is a DR
+          Ptr<NetDevice> ndLocal = *i;
+          uint32_t ifIndexLocal = FindIfIndexForDevice(m_node, ndLocal);
+          Ipv4Address addrLocal = ipv4Local->GetAddress(ifIndexLocal);
+          Ipv4Mask maskLocal = ipv4Local->GetNetworkMask(ifIndexLocal);
+
+          GlobalRoutingLSA *pLSA = new GlobalRoutingLSA;
+          pLSA->SetLSType (GlobalRoutingLSA::NetworkLSA);
+          pLSA->SetLinkStateId (addrLocal);
+          pLSA->SetAdvertisingRouter (m_routerId);
+          pLSA->SetNetworkLSANetworkMask (maskLocal);
+          pLSA->SetStatus (GlobalRoutingLSA::LSA_SPF_NOT_EXPLORED);
+// Build list of AttachedRouters
+          Ptr<Channel> ch = ndLocal->GetChannel();
+          uint32_t nDevices = ch->GetNDevices();
+          NS_ASSERT (nDevices);
+          for (uint32_t i = 0; i < nDevices; i++)
+            {
+              Ptr<NetDevice> tempNd = ch->GetDevice (i);
+              NS_ASSERT (tempNd);
+              Ptr<Node> tempNode = tempNd->GetNode ();
+              uint32_t tempIfIndex = FindIfIndexForDevice (tempNode, tempNd);
+              Ptr<Ipv4> tempIpv4 = tempNode->QueryInterface<Ipv4> (Ipv4::iid);
+              NS_ASSERT (tempIpv4);
+              Ipv4Address tempAddr = tempIpv4->GetAddress(tempIfIndex);
+              pLSA->AddAttachedRouter (tempAddr);
+            }
+          m_LSAs.push_back (pLSA);
+          NS_LOG_LOGIC (*pLSA);
+        }
+    }
+
+  return m_LSAs.size ();
+}
+
+  Ipv4Address
+GlobalRouter::FindDesignatedRouterForLink (Ptr<Node> node, 
+  Ptr<NetDevice> ndLocal) const
+{
+  uint32_t ifIndexLocal = FindIfIndexForDevice(node, ndLocal);
+  Ptr<Ipv4> ipv4Local = m_node->QueryInterface<Ipv4> (Ipv4::iid);
+  NS_ASSERT (ipv4Local);
+  Ipv4Address addrLocal = ipv4Local->GetAddress(ifIndexLocal);
+  Ipv4Mask maskLocal = ipv4Local->GetNetworkMask(ifIndexLocal);
+
+  Ptr<Channel> ch = ndLocal->GetChannel();
+  uint32_t nDevices = ch->GetNDevices();
+  NS_ASSERT (nDevices);
+  Ipv4Address lowest = addrLocal;
+  // iterate all NetDevices and return the lowest numbered IP address 
+  for (uint32_t i = 0; i < nDevices; i++)
+    {
+      Ptr<NetDevice> tempNd = ch->GetDevice (i);
+      NS_ASSERT (tempNd);
+      Ptr<Node> tempNode = tempNd->GetNode ();
+      uint32_t tempIfIndex = FindIfIndexForDevice (tempNode, tempNd);
+      Ptr<Ipv4> tempIpv4 = tempNode->QueryInterface<Ipv4> (Ipv4::iid);
+      NS_ASSERT (tempIpv4);
+      Ipv4Address tempAddr = tempIpv4->GetAddress(tempIfIndex);
+      if (tempAddr < addrLocal)
+        {
+          addrLocal = tempAddr;
+        }
+    }
+  return addrLocal;
+}
+
+  uint32_t 
+GlobalRouter::GetNumLSAs (void) const
+{
+  NS_LOG_FUNCTION;
+  return m_LSAs.size ();
+}
+
+//
+// Get the nth link state advertisement from this router.
+//
+  bool
+GlobalRouter::GetLSA (uint32_t n, GlobalRoutingLSA &lsa) const
+{
+  NS_LOG_FUNCTION;
+  NS_ASSERT_MSG(lsa.IsEmpty(), "GlobalRouter::GetLSA (): Must pass empty LSA");
+//
+// All of the work was done in GetNumLSAs.  All we have to do here is to
+// walk the list of link state advertisements created there and return the 
+// one the client is interested in.
+//
+  ListOfLSAs_t::const_iterator i = m_LSAs.begin ();
+  uint32_t j = 0;
+
+  for (; i != m_LSAs.end (); i++, j++)
+    {
+      if (j == n)
+        {
+          GlobalRoutingLSA *p = *i;
+          lsa = *p;
+          return true;
+        }
+    }
+
+  return false;
+}
+
+//
+// Link through the given channel and find the net device that's on the
+// other end.  This only makes sense with a point-to-point channel.
+//
+  Ptr<NetDevice>
+GlobalRouter::GetAdjacent(Ptr<NetDevice> nd, Ptr<Channel> ch) const
+{
+  NS_LOG_FUNCTION;
+  NS_ASSERT_MSG(ch->GetNDevices() == 2, 
+    "GlobalRouter::GetAdjacent (): Channel with other than two devices");
+//
+// This is a point to point channel with two endpoints.  Get both of them.
+//
+  Ptr<NetDevice> nd1 = ch->GetDevice(0);
+  Ptr<NetDevice> nd2 = ch->GetDevice(1);
+//
+// One of the endpoints is going to be "us" -- that is the net device attached
+// to the node on which we're running -- i.e., "nd".  The other endpoint (the
+// one to which we are connected via the channel) is the adjacent router.
+//
+  if (nd1 == nd)
+    {
+      return nd2;
+    }
+  else if (nd2 == nd)
+    {
+      return nd1;
+    }
+  else
+    {
+      NS_ASSERT_MSG(false,
+        "GlobalRouter::GetAdjacent (): Wrong or confused channel?");
+      return 0;
+    }
+}
+
+//
+// Given a node and a net device, find the IPV4 interface index that 
+// corresponds to that net device.
+//
+  uint32_t
+GlobalRouter::FindIfIndexForDevice(Ptr<Node> node, Ptr<NetDevice> nd) const
+{
+  NS_LOG_FUNCTION;
+  Ptr<Ipv4> ipv4 = node->QueryInterface<Ipv4> (Ipv4::iid);
+  NS_ASSERT_MSG(ipv4, "QI for <Ipv4> interface failed");
+  for (uint32_t i = 0; i < ipv4->GetNInterfaces(); ++i )
+    {
+      if (ipv4->GetNetDevice(i) == nd) 
+        {
+          return i;
+        }
+    }
+
+  NS_ASSERT_MSG(0, "Cannot find interface for device");
+  return 0;
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/routing/global-routing/global-router-interface.h	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,672 @@
+/* -*- 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
+ *
+ * Authors:  Craig Dowell (craigdo@ee.washington.edu)
+ *           Tom Henderson (tomhend@u.washington.edu)
+ */
+
+#ifndef GLOBAL_ROUTER_INTERFACE_H
+#define GLOBAL_ROUTER_INTERFACE_H
+
+#include <stdint.h>
+#include <list>
+#include "ns3/object.h"
+#include "ns3/ptr.h"
+#include "ns3/node.h"
+#include "ns3/channel.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/global-route-manager.h"
+
+namespace ns3 {
+
+/**
+ * @brief A single link record for a link state advertisement.
+ *
+ * The GlobalRoutingLinkRecord is modeled after the OSPF link record field of
+ * a Link State Advertisement.  Right now we will only see two types of link
+ * records corresponding to a stub network and a point-to-point link (channel).
+ */
+class GlobalRoutingLinkRecord
+{
+public:
+/**
+ * @enum LinkType
+ * @brief Enumeration of the possible types of Global Routing Link Records.
+ *
+ * These values are defined in the OSPF spec.  We currently only use 
+ * PointToPoint and StubNetwork types.
+ */
+  enum LinkType {
+    Unknown = 0,        /**< Uninitialized Link Record */
+    PointToPoint,       /**< Record representing a point to point channel */
+    TransitNetwork,     /**< Unused -- for future OSPF compatibility  */
+    StubNetwork,        /**< Record represents a leaf node network */
+    VirtualLink         /**< Unused -- for future OSPF compatibility  */
+  };
+
+/**
+ * @brief Construct an empty ("uninitialized") Global Routing Link Record.
+ *
+ * The Link ID and Link Data Ipv4 addresses are set to "0.0.0.0";
+ * The Link Type is set to Unknown;
+ * The metric is set to 0.
+ */
+  GlobalRoutingLinkRecord ();
+
+/**
+ * Construct an initialized Global Routing Link Record.
+ *
+ * @param linkType The type of link record to construct.
+ * @param linkId The link ID for the record.
+ * @param linkData The link data field for the record.
+ * @param metric The metric field for the record.
+ * @see LinkType
+ * @see SetLinkId
+ * @see SetLinkData
+ */
+  GlobalRoutingLinkRecord (
+    LinkType    linkType, 
+    Ipv4Address linkId, 
+    Ipv4Address linkData, 
+    uint32_t    metric);
+
+/**
+ * @brief Destroy a Global Routing Link Record.
+ *
+ * Currently does nothing.  Here as a placeholder only.
+ */
+  ~GlobalRoutingLinkRecord ();
+
+/**
+ * Get the Link ID field of the Global Routing Link Record.
+ *
+ * For an OSPF type 1 link (PointToPoint) the Link ID will be the Router ID
+ * of the neighboring router.
+ *
+ * For an OSPF type 3 link (StubNetwork), the Link ID will be the adjacent
+ * neighbor's IP address
+ *
+ * @returns The Ipv4Address corresponding to the Link ID field of the record.
+ */
+  Ipv4Address GetLinkId(void) const;
+
+/**
+ * @brief Set the Link ID field of the Global Routing Link Record.
+ *
+ * For an OSPF type 1 link (PointToPoint) the Link ID must be the Router ID
+ * of the neighboring router.
+ *
+ * For an OSPF type 3 link (StubNetwork), the Link ID must be the adjacent
+ * neighbor's IP address
+ *
+ * @param addr An Ipv4Address to store in the Link ID field of the record.
+ */
+  void SetLinkId(Ipv4Address addr);
+
+/**
+ * @brief Get the Link Data field of the Global Routing Link Record.
+ *
+ * For an OSPF type 1 link (PointToPoint) the Link Data will be the IP
+ * address of the node of the local side of the link.
+ *
+ * For an OSPF type 3 link (StubNetwork), the Link Data will be the
+ * network mask
+ *
+ * @returns The Ipv4Address corresponding to the Link Data field of the record.
+ */
+  Ipv4Address GetLinkData(void) const;
+
+/**
+ * @brief Set the Link Data field of the Global Routing Link Record.
+ *
+ * For an OSPF type 1 link (PointToPoint) the Link Data must be the IP
+ * address of the node of the local side of the link.
+ *
+ * For an OSPF type 3 link (StubNetwork), the Link Data must be set to the
+ * network mask
+ *
+ * @param addr An Ipv4Address to store in the Link Data field of the record.
+ */
+  void SetLinkData(Ipv4Address addr);
+
+/**
+ * @brief Get the Link Type field of the Global Routing Link Record.
+ *
+ * The Link Type describes the kind of link a given record represents.  The
+ * values are defined by OSPF.
+ *
+ * @see LinkType
+ * @returns The LinkType of the current Global Routing Link Record.
+ */
+  LinkType GetLinkType(void) const;
+
+/**
+ * @brief Set the Link Type field of the Global Routing Link Record.
+ *
+ * The Link Type describes the kind of link a given record represents.  The
+ * values are defined by OSPF.
+ *
+ * @see LinkType
+ * @param linkType The new LinkType for the current Global Routing Link Record.
+ */
+  void SetLinkType(LinkType linkType);
+
+/**
+ * @brief Get the Metric Data field of the Global Routing Link Record.
+ *
+ * The metric is an abstract cost associated with forwarding a packet across
+ * a link.  A sum of metrics must have a well-defined meaning.  That is, you
+ * shouldn't use bandwidth as a metric (how does the sum of the bandwidth of
+ * two hops relate to the cost of sending a packet); rather you should use
+ * something like delay.
+ *
+ * @returns The metric field of the Global Routing Link Record.
+ */
+  uint32_t GetMetric(void) const;
+
+/**
+ * @brief Set the Metric Data field of the Global Routing Link Record.
+ *
+ * The metric is an abstract cost associated with forwarding a packet across
+ * a link.  A sum of metrics must have a well-defined meaning.  That is, you
+ * shouldn't use bandwidth as a metric (how does the sum of the bandwidth of
+ * two hops relate to the cost of sending a packet); rather you should use
+ * something like delay.
+ *
+ * @param metric The new metric for the current Global Routing Link Record.
+ */
+  void SetMetric(uint32_t metric);
+
+private:
+/**
+ * m_linkId and m_linkData are defined by OSPF to have different meanings 
+ * depending on the type of link a given link records represents.  They work
+ * together.
+ *
+ * For Type 1 link (PointToPoint), set m_linkId to Router ID of 
+ * neighboring router.
+ *
+ * For Type 3 link (Stub), set m_linkId to neighbor's IP address
+ */
+  Ipv4Address m_linkId;         
+
+/**
+ * m_linkId and m_linkData are defined by OSPF to have different meanings 
+ * depending on the type of link a given link records represents.  They work
+ * together.
+ *
+ * For Type 1 link (PointToPoint), set m_linkData to local IP address  
+ *
+ * For Type 3 link (Stub), set m_linkData to mask
+ */
+  Ipv4Address m_linkData;    // for links to RouterLSA, 
+
+/**
+ * The type of the Global Routing Link Record.  Defined in the OSPF spec.  
+ * We currently only use PointToPoint and StubNetwork types.
+ */
+  LinkType m_linkType;
+
+/**
+ * The metric for a given link.
+ *
+ * A metric is abstract cost associated with forwarding a packet across a 
+ * link.  A sum of metrics must have a well-defined meaning.  That is, you 
+ * shouldn't use bandwidth as a metric (how does the sum of the bandwidth 
+ * of two hops relate to the cost of sending a packet); rather you should
+ * use something like delay.
+ */
+  uint32_t m_metric;  
+};
+
+/**  
+ * @brief a Link State Advertisement (LSA) for a router, used in global 
+ * routing.
+ * 
+ * Roughly equivalent to a global incarnation of the OSPF link state header
+ * combined with a list of Link Records.  Since it's global, there's
+ * no need for age or sequence number.  See RFC 2328, Appendix A.
+ */
+class GlobalRoutingLSA
+{
+public:
+/**
+ * @enum LSType
+ * @brief corresponds to LS type field of RFC 2328 OSPF LSA header
+ */
+  enum LSType {
+    Unknown = 0,        /**< Uninitialized Type */
+    RouterLSA,
+    NetworkLSA,
+    SummaryLSA,
+    SummaryLSA_ASBR,
+    ASExternalLSAs
+  };
+/**
+ * @enum SPFStatus
+ * @brief Enumeration of the possible values of the status flag in the Routing 
+ * Link State Advertisements.
+ */
+  enum SPFStatus {
+    LSA_SPF_NOT_EXPLORED = 0,	/**< New vertex not yet considered */
+    LSA_SPF_CANDIDATE,		/**< Vertex is in the SPF candidate queue */
+    LSA_SPF_IN_SPFTREE		/**< Vertex is in the SPF tree */
+  };
+/**
+ * @brief Create a blank Global Routing Link State Advertisement.  
+ *
+ * On completion Ipv4Address variables initialized to 0.0.0.0 and the 
+ * list of Link State Records is empty.
+ */
+  GlobalRoutingLSA();
+
+/**
+ * @brief Create an initialized Global Routing Link State Advertisement.  
+ *
+ * On completion the list of Link State Records is empty.
+ *
+ * @param status The status to of the new LSA.
+ * @param linkStateId The Ipv4Address for the link state ID field.
+ * @param advertisingRtr The Ipv4Address for the advertising router field.
+ */
+  GlobalRoutingLSA(SPFStatus status, Ipv4Address linkStateId, 
+    Ipv4Address advertisingRtr);
+
+/**
+ * @brief Copy constructor for a Global Routing Link State Advertisement.
+ *
+ * Takes a piece of memory and constructs a semantically identical copy of
+ * the given LSA.
+ *
+ * @param lsa The existing LSA to be used as the source.
+ */
+  GlobalRoutingLSA (GlobalRoutingLSA& lsa);
+
+/**
+ * @brief Destroy an existing Global Routing Link State Advertisement.
+ *
+ * Any Global Routing Link Records present in the list are freed.
+ */
+  ~GlobalRoutingLSA();
+
+/**
+ * @brief Assignment operator for a Global Routing Link State Advertisement.
+ *
+ * Takes an existing Global Routing Link State Advertisement and overwrites
+ * it to make a semantically identical copy of a given prototype LSA.
+ *
+ * If there are any Global Routing Link Records present in the existing 
+ * LSA, they are freed before the assignment happens.
+ *
+ * @param lsa The existing LSA to be used as the source.
+ * @returns Reference to the overwritten LSA.
+ */
+  GlobalRoutingLSA& operator= (const GlobalRoutingLSA& lsa);
+
+/**
+ * @brief Copy any Global Routing Link Records in a given Global Routing Link
+ * State Advertisement to the current LSA.  
+ * 
+ * Existing Link Records are not deleted -- this is a concatenation of Link 
+ * Records.
+ *
+ * @see ClearLinkRecords ()
+ * @param lsa The LSA to copy the Link Records from.
+ */
+  void CopyLinkRecords (const GlobalRoutingLSA& lsa);
+
+/**
+ * @brief Add a given Global Routing Link Record to the LSA.
+ *
+ * @param lr The Global Routing Link Record to be added.
+ * @returns The number of link records in the list.
+ */
+  uint32_t AddLinkRecord (GlobalRoutingLinkRecord* lr);
+
+/**
+ * @brief Return the number of Global Routing Link Records in the LSA.
+ *
+ * @returns The number of link records in the list.
+ */
+  uint32_t GetNLinkRecords (void) const;
+
+/**
+ * @brief Return a pointer to the specified Global Routing Link Record.
+ *
+ * @param n The LSA number desired.
+ * @returns The number of link records in the list.
+ */
+  GlobalRoutingLinkRecord* GetLinkRecord (uint32_t n) const;
+
+/**
+ * @brief Release all of the Global Routing Link Records present in the Global
+ * Routing Link State Advertisement and make the list of link records empty.
+ */
+  void ClearLinkRecords(void);
+
+/**
+ * @brief Check to see if the list of Global Routing Link Records present in the
+ * Global Routing Link State Advertisement is empty.
+ *
+ * @returns True if the list is empty, false otherwise.
+ */
+  bool IsEmpty(void) const;
+
+/**
+ * @brief Print the contents of the Global Routing Link State Advertisement and
+ * any Global Routing Link Records present in the list.  Quite verbose.
+ */
+  void Print (std::ostream &os) const;
+
+/**
+ * @brief Return the LSType field of the LSA 
+ */
+  LSType GetLSType (void) const;
+/**
+ * @brief Set the LS type field of the LSA
+ */
+  void SetLSType (LSType typ);
+
+/**
+ * @brief Get the Link State ID as defined by the OSPF spec.  We always set it
+ * to the router ID of the router making the advertisement.
+ *
+ * @see RoutingEnvironment::AllocateRouterId ()
+ * @see GlobalRouting::GetRouterId ()
+ * @returns The Ipv4Address stored as the link state ID.
+ */
+  Ipv4Address GetLinkStateId (void) const;
+
+/**
+ * @brief Set the Link State ID is defined by the OSPF spec.  We always set it
+ * to the router ID of the router making the advertisement.
+ *
+ * @see RoutingEnvironment::AllocateRouterId ()
+ * @see GlobalRouting::GetRouterId ()
+ */
+  void SetLinkStateId (Ipv4Address addr);
+
+/**
+ * @brief Get the Advertising Router as defined by the OSPF spec.  We always
+ * set it to the router ID of the router making the advertisement.
+ *
+ * @see RoutingEnvironment::AllocateRouterId ()
+ * @see GlobalRouting::GetRouterId ()
+ * @returns The Ipv4Address stored as the advetising router.
+ */
+  Ipv4Address GetAdvertisingRouter (void) const;
+
+/**
+ * @brief Set the Advertising Router as defined by the OSPF spec.  We always
+ * set it to the router ID of the router making the advertisement.
+ *
+ * @see RoutingEnvironment::AllocateRouterId ()
+ * @see GlobalRouting::GetRouterId ()
+ */
+  void SetAdvertisingRouter (Ipv4Address  rtr);
+
+/**
+ * @brief For a Network LSA, set the Network Mask field that precedes
+ * the list of attached routers.
+ */
+  void SetNetworkLSANetworkMask (Ipv4Mask mask);
+
+/**
+ * @brief For a Network LSA, get the Network Mask field that precedes
+ * the list of attached routers.
+ * 
+ * @returns the NetworkLSANetworkMask 
+ */
+  Ipv4Mask GetNetworkLSANetworkMask (void) const;
+
+/**
+ * @brief Add an attached router to the list in the NetworkLSA
+ *
+ * @param addr The Ipv4Address of the interface on the network link
+ * @returns The number of addresses in the list.
+ */
+  uint32_t AddAttachedRouter (Ipv4Address addr);
+
+/**
+ * @brief Return the number of attached routers listed in the NetworkLSA
+ *
+ * @returns The number of attached routers.
+ */
+  uint32_t GetNAttachedRouters (void) const;
+
+/**
+ * @brief Return an Ipv4Address corresponding to the specified attached router
+ *
+ * @param n The attached router number desired (number in the list).
+ * @returns The Ipv4Address of the requested router
+ */
+  Ipv4Address GetAttachedRouter (uint32_t n) const;
+
+/**
+ * @brief Get the SPF status of the advertisement.
+ *
+ * @see SPFStatus
+ * @returns The SPFStatus of the LSA.
+ */
+  SPFStatus GetStatus (void) const;
+
+/**
+ * @brief Set the SPF status of the advertisement
+ *
+ * @see SPFStatus
+ */
+  void SetStatus (SPFStatus status);
+
+private:
+/**
+ * The type of the LSA.  Each LSA type has a separate advertisement
+ * format.
+ */
+  LSType m_lsType;
+/**
+ * The Link State ID is defined by the OSPF spec.  We always set it to the
+ * router ID of the router making the advertisement.
+ *
+ * @see RoutingEnvironment::AllocateRouterId ()
+ * @see GlobalRouting::GetRouterId ()
+ */
+  Ipv4Address  m_linkStateId;
+
+/**
+ * The Advertising Router is defined by the OSPF spec.  We always set it to 
+ * the router ID of the router making the advertisement.
+ *
+ * @see RoutingEnvironment::AllocateRouterId ()
+ * @see GlobalRouting::GetRouterId ()
+ */
+  Ipv4Address  m_advertisingRtr;
+
+/**
+ * A convenience typedef to avoid too much writers cramp.
+ */
+  typedef std::list<GlobalRoutingLinkRecord*> ListOfLinkRecords_t;
+
+/**
+ * Each Link State Advertisement contains a number of Link Records that
+ * describe the kinds of links that are attached to a given node.  We 
+ * consider PointToPoint and StubNetwork links.
+ *
+ * m_linkRecords is an STL list container to hold the Link Records that have
+ * been discovered and prepared for the advertisement.
+ *
+ * @see GlobalRouting::DiscoverLSAs ()
+ */
+  ListOfLinkRecords_t m_linkRecords;
+
+/**
+ * Each Network LSA contains the network mask of the attached network
+ */
+  Ipv4Mask m_networkLSANetworkMask;
+
+/**
+ * A convenience typedef to avoid too much writers cramp.
+ */
+  typedef std::list<Ipv4Address> ListOfAttachedRouters_t;
+
+/**
+ * Each Network LSA contains a list of attached routers
+ *
+ * m_attachedRouters is an STL list container to hold the addresses that have
+ * been discovered and prepared for the advertisement.
+ *
+ * @see GlobalRouting::DiscoverLSAs ()
+ */
+  ListOfAttachedRouters_t m_attachedRouters;
+
+/**
+ * This is a tristate flag used internally in the SPF computation to mark
+ * if an SPFVertex (a data structure representing a vertex in the SPF tree
+ * -- a router) is new, is a candidate for a shortest path, or is in its
+ * proper position in the tree.
+ */
+  SPFStatus m_status;
+};
+
+std::ostream& operator<< (std::ostream& os, GlobalRoutingLSA& lsa);
+
+/**
+ * @brief An interface aggregated to a node to provide global routing info
+ *
+ * An interface aggregated to a node that provides global routing information
+ * to a global route manager.  The presence of the interface indicates that
+ * the node is a router.  The interface is the mechanism by which the router
+ * advertises its connections to neighboring routers.  We're basically 
+ * allowing the route manager to query for link state advertisements.
+ */
+class GlobalRouter : public Object
+{
+public:
+/**
+ * @brief The Interface ID of the Global Router interface.
+ *
+ * @see Object::QueryInterface ()
+ */
+  static const InterfaceId iid;
+
+/**
+ * @brief Create a Global Router class and aggregate its interface onto the 
+ * Node provided.
+ *
+ * @param node The existing Node onto which this router will be aggregated.
+ */
+  GlobalRouter (Ptr<Node> node);
+
+/**
+ * @brief Get the Router ID associated with this Global Router.
+ *
+ * The Router IDs are allocated in the RoutingEnvironment -- one per Router, 
+ * starting at 0.0.0.1 and incrementing with each instantiation of a router.
+ *
+ * @see RoutingEnvironment::AllocateRouterId ()
+ * @returns The Router ID associated with the Global Router.
+ */
+  Ipv4Address GetRouterId (void) const;
+
+/**
+ * @brief Walk the connected channels, discover the adjacent routers and build
+ * the associated number of Global Routing Link State Advertisements that 
+ * this router can export.
+ *
+ * This is a fairly expensive operation in that every time it is called
+ * the current list of LSAs is built by walking connected point-to-point
+ * channels and peeking into adjacent IPV4 stacks to get address information.
+ * This is done to allow for limited dymanics of the Global Routing 
+ * environment.  By that we mean that you can discover new link state 
+ * advertisements after a network topology change by calling DiscoverLSAs 
+ * and then by reading those advertisements.
+ *
+ * @see GlobalRoutingLSA
+ * @see GlobalRouter::GetLSA ()
+ * @returns The number of Global Routing Link State Advertisements.
+ */
+  uint32_t DiscoverLSAs (void);
+
+/**
+ * @brief Get the Number of Global Routing Link State Advertisements that this
+ * router can export.
+ *
+ * To get meaningful information you must have previously called DiscoverLSAs.
+ * After you know how many LSAs are present in the router, you may call 
+ * GetLSA () to retrieve the actual advertisement.
+ *
+ * @see GlobalRouterLSA
+ * @see GlobalRouting::DiscoverLSAs ()
+ * @see GlobalRouting::GetLSA ()
+ * @returns The number of Global Routing Link State Advertisements.
+ */
+  uint32_t GetNumLSAs (void) const;
+
+/**
+ * @brief Get a Global Routing Link State Advertisements that this router has 
+ * said that it can export.
+ *
+ * This is a fairly inexpensive expensive operation in that the hard work
+ * was done in GetNumLSAs.  We just copy the indicated Global Routing Link
+ * State Advertisement into the requested GlobalRoutingLSA object.
+ *
+ * You must call GlobalRouter::GetNumLSAs before calling this method in 
+ * order to discover the adjacent routers and build the advertisements.
+ * GetNumLSAs will return the number of LSAs this router advertises.  
+ * The parameter n (requested LSA number) must be in the range 0 to 
+ * GetNumLSAs() - 1.
+ *
+ * @see GlobalRoutingLSA
+ * @see GlobalRouting::GetNumLSAs ()
+ * @param n The index number of the LSA you want to read.
+ * @param lsa The GlobalRoutingLSA class to receive the LSA information.
+ * @returns The number of Global Router Link State Advertisements.
+ */
+  bool GetLSA (uint32_t n, GlobalRoutingLSA &lsa) const;
+
+private:
+  virtual ~GlobalRouter ();
+  void ClearLSAs (void);
+
+  Ptr<NetDevice> GetAdjacent(Ptr<NetDevice> nd, Ptr<Channel> ch) const;
+  uint32_t FindIfIndexForDevice(Ptr<Node> node, Ptr<NetDevice> nd) const;
+  Ipv4Address FindDesignatedRouterForLink (Ptr<Node> node,   
+    Ptr<NetDevice> ndLocal) const;
+
+  Ptr<Node>     m_node;
+
+  typedef std::list<GlobalRoutingLSA*> ListOfLSAs_t;
+  ListOfLSAs_t m_LSAs;
+
+  Ipv4Address m_routerId;
+
+  // inherited from Object
+  virtual void DoDispose (void);
+
+/**
+ * @brief Global Router copy construction is disallowed.
+ */
+  GlobalRouter (GlobalRouter& sr);
+
+/**
+ * @brief Global Router assignment operator is disallowed.
+ */
+  GlobalRouter& operator= (GlobalRouter& sr);
+};
+
+} // namespace ns3
+
+#endif /* GLOBAL_ROUTER_INTERFACE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/routing/global-routing/waf	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,1 @@
+exec "`dirname "$0"`"/../../../waf "$@"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/routing/global-routing/wscript	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,17 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def build(bld):
+    module = bld.create_ns3_module('global-routing', ['node'])
+    module.source = [
+        'global-router-interface.cc',
+        'global-route-manager.cc',
+        'global-route-manager-impl.cc',
+        'candidate-queue.cc',
+        ]
+    headers = bld.create_obj('ns3header')
+    headers.source = [
+        'global-router-interface.h',
+        'global-route-manager.h',
+        'candidate-queue.h',
+        ]
+
--- a/src/simulator/event-id.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/simulator/event-id.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -30,7 +30,7 @@
     m_uid (0)
 {}
   
-EventId::EventId (EventImpl *impl, uint64_t ts, uint32_t uid)
+EventId::EventId (const Ptr<EventImpl> &impl, uint64_t ts, uint32_t uid)
   : m_eventImpl (impl),
     m_ts (ts),
     m_uid (uid)
@@ -38,26 +38,22 @@
 void 
 EventId::Cancel (void)
 {
-  if (!IsExpired ())
-    {
-      m_eventImpl->Cancel ();
-      m_eventImpl = 0;
-    }
+  Simulator::Cancel (*this);
 }
 bool 
-EventId::IsExpired (void)
+EventId::IsExpired (void) const
 {
   return Simulator::IsExpired (*this);
 }
 bool 
-EventId::IsRunning (void)
+EventId::IsRunning (void) const
 {
   return !IsExpired ();
 }
 EventImpl *
-EventId::GetEventImpl (void) const
+EventId::PeekEventImpl (void) const
 {
-  return m_eventImpl;
+  return PeekPointer (m_eventImpl);
 }
 uint64_t 
 EventId::GetTs (void) const
--- a/src/simulator/event-id.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/simulator/event-id.h	Fri Sep 28 11:59:46 2007 +0100
@@ -22,6 +22,8 @@
 #define EVENT_ID_H
 
 #include <stdint.h>
+#include "ns3/ptr.h"
+#include "event-impl.h"
 
 namespace ns3 {
 
@@ -33,7 +35,7 @@
 class EventId {
 public:
   EventId ();
-  EventId (EventImpl *impl, uint64_t ts, uint32_t uid);
+  EventId (const Ptr<EventImpl> &impl, uint64_t ts, uint32_t uid);
   /**
    * This method is syntactic sugar for the ns3::Simulator::cancel
    * method.
@@ -44,19 +46,19 @@
    * method.
    * \returns true if the event has expired, false otherwise.
    */
-  bool IsExpired (void);
-  bool IsRunning (void);
+  bool IsExpired (void) const;
+  bool IsRunning (void) const;
 public:
   /* The following methods are semi-private
    * they are supposed to be invoked only by
    * subclasses of the Scheduler base class.
    */
-  EventImpl *GetEventImpl (void) const;
+  EventImpl *PeekEventImpl (void) const;
   uint64_t GetTs (void) const;
   uint32_t GetUid (void) const;
 private:
   friend bool operator == (const EventId &a, const EventId &b);
-  EventImpl *m_eventImpl;
+  Ptr<EventImpl> m_eventImpl;
   uint64_t m_ts;
   uint32_t m_uid;
 };
--- a/src/simulator/event-impl.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/simulator/event-impl.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -29,7 +29,8 @@
 {}
 
 EventImpl::EventImpl ()
-  : m_cancel (false)
+  : m_cancel (false),
+    m_count (1)
 {}
 void 
 EventImpl::Invoke (void)
--- a/src/simulator/event-impl.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/simulator/event-impl.h	Fri Sep 28 11:59:46 2007 +0100
@@ -28,6 +28,8 @@
 class EventImpl {
 public:
   EventImpl ();
+  inline void Ref (void) const;
+  inline void Unref (void) const;
   virtual ~EventImpl () = 0;
   void Invoke (void);
   void Cancel (void);
@@ -37,8 +39,28 @@
 private:
   friend class Event;
   bool m_cancel;
+  mutable uint32_t m_count;
 };
 
 }; // namespace ns3
 
+namespace ns3 {
+
+void
+EventImpl::Ref (void) const
+{
+  m_count++;
+}
+void
+EventImpl::Unref (void) const
+{
+  m_count--;
+  if (m_count == 0)
+    {
+      delete this;
+    }
+}
+
+} // namespace ns3
+
 #endif /* EVENT_IMPL_H */
--- a/src/simulator/high-precision-128.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/simulator/high-precision-128.h	Fri Sep 28 11:59:46 2007 +0100
@@ -222,7 +222,9 @@
       HP128INC (m_nslowcmps);
       return SlowCompare (o);
     }
-
+  // The below statement is unreachable but necessary for optimized
+  // builds with gcc-4.0.x due to a compiler bug.
+  return 0;  
 }
 HighPrecision 
 HighPrecision::Zero (void)
--- a/src/simulator/scheduler-heap.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/simulator/scheduler-heap.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -170,7 +170,7 @@
 }
 
 bool
-SchedulerHeap::RealIsEmpty (void) const
+SchedulerHeap::IsEmpty (void) const
 {
   return (m_heap.size () == 1)?true:false;
 }
@@ -223,9 +223,11 @@
 
 
 void
-SchedulerHeap::RealInsert (EventId id)
+SchedulerHeap::Insert (const EventId &id)
 {
-  EventImpl *event = id.GetEventImpl ();
+  // acquire single ref
+  EventImpl *event = id.PeekEventImpl ();
+  event->Ref ();
   Scheduler::EventKey key;
   key.m_ts = id.GetTs ();
   key.m_uid = id.GetUid ();
@@ -234,29 +236,34 @@
 }
 
 EventId
-SchedulerHeap::RealPeekNext (void) const
+SchedulerHeap::PeekNext (void) const
 {
   std::pair<EventImpl *,Scheduler::EventKey> next = m_heap[Root ()];
   return EventId (next.first, next.second.m_ts, next.second.m_uid);
 }
-void     
-SchedulerHeap::RealRemoveNext (void)
+EventId
+SchedulerHeap::RemoveNext (void)
 {
+  std::pair<EventImpl *,Scheduler::EventKey> next = m_heap[Root ()];
   Exch (Root (), Last ());
   m_heap.pop_back ();
   TopDown (Root ());
+  return EventId (Ptr<EventImpl> (next.first, false), next.second.m_ts, next.second.m_uid);
 }
 
 
 bool
-SchedulerHeap::RealRemove (EventId id)
+SchedulerHeap::Remove (const EventId &id)
 {
   uint32_t uid = id.GetUid ();
   for (uint32_t i = 1; i < m_heap.size (); i++)
     {
       if (uid == m_heap[i].second.m_uid)
         {
-          NS_ASSERT (m_heap[i].first == id.GetEventImpl ());
+          NS_ASSERT (m_heap[i].first == id.PeekEventImpl ());
+          std::pair<EventImpl *,Scheduler::EventKey> next = m_heap[i];
+          // release single ref
+          next.first->Unref ();
           Exch (i, Last ());
           m_heap.pop_back ();
           TopDown (i);
--- a/src/simulator/scheduler-heap.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/simulator/scheduler-heap.h	Fri Sep 28 11:59:46 2007 +0100
@@ -35,13 +35,13 @@
   SchedulerHeap ();
   virtual ~SchedulerHeap ();
 
+  virtual void Insert (const EventId &id);
+  virtual bool IsEmpty (void) const;
+  virtual EventId PeekNext (void) const;
+  virtual EventId RemoveNext (void);
+  virtual bool Remove (const EventId &ev);
+
 private:
-  virtual void RealInsert (EventId id);
-  virtual bool RealIsEmpty (void) const;
-  virtual EventId RealPeekNext (void) const;
-  virtual void RealRemoveNext (void);
-  virtual bool RealRemove (EventId ev);
-
   typedef std::vector<std::pair<EventImpl *, Scheduler::EventKey> > BinaryHeap;
 
   inline uint32_t Parent (uint32_t id) const;
--- a/src/simulator/scheduler-list.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/simulator/scheduler-list.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -67,10 +67,12 @@
 }
 
 void
-SchedulerList::RealInsert (EventId id)
+SchedulerList::Insert (const EventId &id)
 {
   Scheduler::EventKey key;
-  EventImpl *event = id.GetEventImpl ();
+  // acquire refcount on EventImpl
+  EventImpl *event = id.PeekEventImpl ();
+  event->Ref ();
   key.m_ts = id.GetTs ();
   key.m_uid = id.GetUid ();
   for (EventsI i = m_events.begin (); i != m_events.end (); i++) 
@@ -84,31 +86,35 @@
   m_events.push_back (std::make_pair (event, key));
 }
 bool 
-SchedulerList::RealIsEmpty (void) const
+SchedulerList::IsEmpty (void) const
 {
   return m_events.empty ();
 }
 EventId
-SchedulerList::RealPeekNext (void) const
+SchedulerList::PeekNext (void) const
 {
   std::pair<EventImpl *, EventKey> next = m_events.front ();
   return EventId (next.first, next.second.m_ts, next.second.m_uid);
 }
 
-void
-SchedulerList::RealRemoveNext (void)
+EventId
+SchedulerList::RemoveNext (void)
 {
+  std::pair<EventImpl *, EventKey> next = m_events.front ();
   m_events.pop_front ();
+  return EventId (Ptr<EventImpl> (next.first,false), next.second.m_ts, next.second.m_uid);
 }
 
 bool
-SchedulerList::RealRemove (EventId id)
+SchedulerList::Remove (const EventId &id)
 {
   for (EventsI i = m_events.begin (); i != m_events.end (); i++) 
     {
       if (i->second.m_uid == id.GetUid ())
         {
-          NS_ASSERT (id.GetEventImpl () == i->first);
+          NS_ASSERT (id.PeekEventImpl () == i->first);
+          // release single acquire ref.
+          i->first->Unref ();
           m_events.erase (i);
           return true;
         }
--- a/src/simulator/scheduler-list.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/simulator/scheduler-list.h	Fri Sep 28 11:59:46 2007 +0100
@@ -37,13 +37,13 @@
   SchedulerList ();
   virtual ~SchedulerList ();
 
+  virtual void Insert (const EventId &id);
+  virtual bool IsEmpty (void) const;
+  virtual EventId PeekNext (void) const;
+  virtual EventId RemoveNext (void);
+  virtual bool Remove (const EventId &ev);
+
  private:
-  virtual void RealInsert (EventId id);
-  virtual bool RealIsEmpty (void) const;
-  virtual EventId RealPeekNext (void) const;
-  virtual void RealRemoveNext (void);
-  virtual bool RealRemove (EventId ev);
-
   inline bool IsLower (Scheduler::EventKey const*a, Scheduler::EventKey const*b) const;
 
   typedef std::list<std::pair<EventImpl*, EventKey> > Events;
--- a/src/simulator/scheduler-map.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/simulator/scheduler-map.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -88,9 +88,11 @@
 
 
 void
-SchedulerMap::RealInsert (EventId id)
+SchedulerMap::Insert (const EventId &id)
 {
-  EventImpl *event = id.GetEventImpl ();
+  // acquire a single ref
+  EventImpl *event = id.PeekEventImpl ();
+  event->Ref ();
   Scheduler::EventKey key;
   key.m_ts = id.GetTs ();
   key.m_uid = id.GetUid ();
@@ -100,33 +102,38 @@
 }
 
 bool
-SchedulerMap::RealIsEmpty (void) const
+SchedulerMap::IsEmpty (void) const
 {
   return m_list.empty ();
 }
 
 EventId
-SchedulerMap::RealPeekNext (void) const
+SchedulerMap::PeekNext (void) const
 {
   EventMapCI i = m_list.begin ();
   NS_ASSERT (i != m_list.end ());
   
   return EventId (i->second, i->first.m_ts, i->first.m_uid);
 }
-void
-SchedulerMap::RealRemoveNext (void)
+EventId
+SchedulerMap::RemoveNext (void)
 {
-  m_list.erase (m_list.begin ());
+  EventMapI i = m_list.begin ();
+  std::pair<Scheduler::EventKey, EventImpl*> next = *i;
+  m_list.erase (i);
+  return EventId (Ptr<EventImpl> (next.second, false), next.first.m_ts, next.first.m_uid);
 }
 
 bool
-SchedulerMap::RealRemove (EventId id)
+SchedulerMap::Remove (const EventId &id)
 {
   Scheduler::EventKey key;
   key.m_ts = id.GetTs ();
   key.m_uid = id.GetUid ();
   EventMapI i = m_list.find (key);
-  NS_ASSERT (i->second == id.GetEventImpl ());
+  NS_ASSERT (i->second == id.PeekEventImpl ());
+  // release single ref.
+  i->second->Unref ();
   m_list.erase (i);
   return true;
 }
--- a/src/simulator/scheduler-map.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/simulator/scheduler-map.h	Fri Sep 28 11:59:46 2007 +0100
@@ -36,12 +36,12 @@
   SchedulerMap ();
   virtual ~SchedulerMap ();
 
+  virtual void Insert (const EventId &id);
+  virtual bool IsEmpty (void) const;
+  virtual EventId PeekNext (void) const;
+  virtual EventId RemoveNext (void);
+  virtual bool Remove (const EventId &ev);
 private:
-  virtual void RealInsert (EventId id);
-  virtual bool RealIsEmpty (void) const;
-  virtual EventId RealPeekNext (void) const;
-  virtual void RealRemoveNext (void);
-  virtual bool RealRemove (EventId ev);
 
   class EventKeyCompare {
   public:
--- a/src/simulator/scheduler.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/simulator/scheduler.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -27,33 +27,4 @@
 Scheduler::~Scheduler () 
 {}
 
-void
-Scheduler::Insert (EventId id)
-{
-  return RealInsert (id);
-}
-bool 
-Scheduler::IsEmpty (void) const
-{
-  return RealIsEmpty ();
-}
-EventId
-Scheduler::PeekNext (void) const
-{
-  NS_ASSERT (!RealIsEmpty ());
-  return RealPeekNext ();
-}
-void 
-Scheduler::RemoveNext (void)
-{
-  NS_ASSERT (!RealIsEmpty ());
-  return RealRemoveNext ();
-}
-bool
-Scheduler::Remove (EventId id)
-{
-  NS_ASSERT (!RealIsEmpty ());
-  return RealRemove (id);
-}
-
 }; // namespace ns3
--- a/src/simulator/scheduler.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/simulator/scheduler.h	Fri Sep 28 11:59:46 2007 +0100
@@ -27,21 +27,18 @@
 
 namespace ns3 {
 
-class EventImpl;
-
 /**
  * \brief Maintain the event list
  *
  * This base class specifies the interface used to maintain the 
  * event list. If you want to provide a new event list scheduler, 
  * you need to create a subclass of this base class and implement 
- * all the private pure virtual methods defined here. Namely:
- *   - ns3::Scheduler::realInsert
- *   - ns3::Scheduler::realIsEmpty
- *   - ns3::Scheduler::realPeekNext
- *   - ns3::Scheduler::realPeekNextKey
- *   - ns3::Scheduler::realRemoveNext
- *   - ns3::Scheduler::realRemove
+ * all the pure virtual methods defined here. Namely:
+ *   - ns3::Scheduler::Insert
+ *   - ns3::Scheduler::IsEmpty
+ *   - ns3::Scheduler::PeekNext
+ *   - ns3::Scheduler::RemoveNext
+ *   - ns3::Scheduler::Remove
  *
  * If you need to provide a new event list scheduler without
  * editing the main simulator class, you need to also implement
@@ -60,41 +57,36 @@
 
   virtual ~Scheduler () = 0;
 
-  void Insert (EventId id);
-  bool IsEmpty (void) const;
-  EventId PeekNext (void) const;
-  void RemoveNext (void);
-  bool Remove (EventId);
-
-private:
   /**
-   * \param id the event id to store.
+   * \param id event to store in the event list
    *
+   * This method takes ownership of the event pointer.
    */
-  virtual void RealInsert (EventId id) = 0;
+  virtual void Insert (const EventId &id) = 0;
   /**
    * \returns true if the event list is empty and false otherwise.
    */
-  virtual bool RealIsEmpty (void) const = 0;
+  virtual bool IsEmpty (void) const = 0;
   /**
-   * \returns a the next earliest event.
+   * \returns a pointer to the next earliest event. The caller
+   *      takes ownership of the returned pointer.
    *
    * This method cannot be invoked if the list is empty.
    */
-  virtual EventId RealPeekNext (void) const = 0;
+  virtual EventId PeekNext (void) const = 0;
   /**
    * This method cannot be invoked if the list is empty.
    * Remove the next earliest event from the event list.
    */
-  virtual void RealRemoveNext (void) = 0;
+  virtual EventId RemoveNext (void) = 0;
   /**
    * \param id the id of the event to remove
-   * \returns true if the event was found and removed
+   * \returns true if the id was found and removed 
    *          successfully, false otherwise.
    *
    * This methods cannot be invoked if the list is empty.
    */
-  virtual bool RealRemove (EventId id) = 0;
+  virtual bool Remove (const EventId &id) = 0;
 };
 
 }; // namespace ns3
--- a/src/simulator/simulator.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/simulator/simulator.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -23,6 +23,7 @@
 #include "scheduler.h"
 #include "event-impl.h"
 
+#include "ns3/ptr.h"
 #include "ns3/assert.h"
 #include "ns3/default-value.h"
 
@@ -61,12 +62,12 @@
   Time Next (void) const;
   void Stop (void);
   void StopAt (Time const &time);
-  EventId Schedule (Time const &time, EventImpl *event);
-  EventId ScheduleNow (EventImpl *event);
-  EventId ScheduleDestroy (EventImpl *event);
-  void Remove (EventId ev);
-  void Cancel (EventId &ev);
-  bool IsExpired (EventId ev);
+  EventId Schedule (Time const &time, const Ptr<EventImpl> &event);
+  EventId ScheduleNow (const Ptr<EventImpl> &event);
+  EventId ScheduleDestroy (const Ptr<EventImpl> &event);
+  void Remove (const EventId &ev);
+  void Cancel (const EventId &ev);
+  bool IsExpired (const EventId &ev);
   void Run (void);
   Time Now (void) const;
 
@@ -114,13 +115,12 @@
 {
   while (!m_destroyEvents.empty ()) 
     {
-      EventImpl *ev = m_destroyEvents.front ().GetEventImpl ();
+      Ptr<EventImpl> ev = m_destroyEvents.front ().PeekEventImpl ();
       m_destroyEvents.pop_front ();
       TRACE ("handle destroy " << ev);
       if (!ev->IsCancelled ())
         {
           ev->Invoke ();
-          delete ev;
         }
     }
   delete m_events;
@@ -138,8 +138,7 @@
 void
 SimulatorPrivate::ProcessOneEvent (void)
 {
-  EventId next = m_events->PeekNext ();
-  m_events->RemoveNext ();
+  EventId next = m_events->RemoveNext ();
 
   NS_ASSERT (next.GetTs () >= m_currentTs);
   --m_unscheduledEvents;
@@ -151,9 +150,8 @@
     {
       m_log << "e "<<next.GetUid () << " " << next.GetTs () << std::endl;
     }
-  EventImpl *event = next.GetEventImpl ();
+  EventImpl *event = next.PeekEventImpl ();
   event->Invoke ();
-  delete event;
 }
 
 bool 
@@ -204,7 +202,7 @@
   m_stopAt = at.GetTimeStep ();
 }
 EventId
-SimulatorPrivate::Schedule (Time const &time, EventImpl *event)
+SimulatorPrivate::Schedule (Time const &time, const Ptr<EventImpl> &event)
 {
   NS_ASSERT (time.IsPositive ());
   NS_ASSERT (time >= TimeStep (m_currentTs));
@@ -221,7 +219,7 @@
   return id;
 }
 EventId
-SimulatorPrivate::ScheduleNow (EventImpl *event)
+SimulatorPrivate::ScheduleNow (const Ptr<EventImpl> &event)
 {
   EventId id (event, m_currentTs, m_uid);
   if (m_logEnable) 
@@ -235,7 +233,7 @@
   return id;
 }
 EventId
-SimulatorPrivate::ScheduleDestroy (EventImpl *event)
+SimulatorPrivate::ScheduleDestroy (const Ptr<EventImpl> &event)
 {
   EventId id (event, m_currentTs, 2);
   m_destroyEvents.push_back (id);
@@ -255,7 +253,7 @@
 }
 
 void
-SimulatorPrivate::Remove (EventId ev)
+SimulatorPrivate::Remove (const EventId &ev)
 {
   if (ev.GetUid () == 2)
     {
@@ -267,7 +265,7 @@
               m_destroyEvents.erase (i);
               break;
             }
-        }
+         }
       return;
     }
   if (IsExpired (ev))
@@ -275,7 +273,8 @@
       return;
     }
   m_events->Remove (ev);
-  delete ev.GetEventImpl ();
+  Cancel (ev);
+
   if (m_logEnable) 
     {
       m_log << "r " << m_currentUid << " " << m_currentTs << " "
@@ -285,19 +284,34 @@
 }
 
 void
-SimulatorPrivate::Cancel (EventId &id)
+SimulatorPrivate::Cancel (const EventId &id)
 {
-  id.Cancel ();
+  if (!IsExpired (id))
+    {
+      id.PeekEventImpl ()->Cancel ();
+    }
 }
 
 bool
-SimulatorPrivate::IsExpired (EventId ev)
+SimulatorPrivate::IsExpired (const EventId &ev)
 {
-  if (ev.GetEventImpl () == 0 ||
+  if (ev.GetUid () == 2)
+    {
+      // destroy events.
+      for (DestroyEvents::iterator i = m_destroyEvents.begin (); i != m_destroyEvents.end (); i++)
+        {
+          if (*i == ev)
+            {
+              return false;
+            }
+         }
+      return true;
+    }
+  if (ev.PeekEventImpl () == 0 ||
       ev.GetTs () < m_currentTs ||
       (ev.GetTs () == m_currentTs &&
        ev.GetUid () <= m_currentUid) ||
-      ev.GetEventImpl ()->IsCancelled ()) 
+      ev.PeekEventImpl ()->IsCancelled ()) 
     {
       return true;
     }
@@ -323,20 +337,20 @@
 
 void Simulator::SetLinkedList (void)
 {
-  Bind ("Scheduler", "List");
+  DefaultValue::Bind ("Scheduler", "List");
 }
 void Simulator::SetBinaryHeap (void)
 {
-  Bind ("Scheduler", "BinaryHeap");
+  DefaultValue::Bind ("Scheduler", "BinaryHeap");
 }
 void Simulator::SetStdMap (void)
 {
-  Bind ("Scheduler", "Map");
+  DefaultValue::Bind ("Scheduler", "Map");
 }
 void 
 Simulator::SetExternal (const std::string &external)
 {
-  Bind ("Scheduler", external);
+  DefaultValue::Bind ("Scheduler", external);
 }
 void Simulator::EnableLogTo (char const *filename)
 {
@@ -398,39 +412,39 @@
   return GetPriv ()->Now ();
 }
 
-EventImpl *
+Ptr<EventImpl>
 Simulator::MakeEvent (void (*f) (void))
 {
     // zero arg version
   class EventFunctionImpl0 : public EventImpl {
   public:
-  	typedef void (*F)(void);
+    typedef void (*F)(void);
       
-  	EventFunctionImpl0 (F function) 
-  		: m_function (function)
-  	{}
-  	virtual ~EventFunctionImpl0 () {}
+    EventFunctionImpl0 (F function) 
+      : m_function (function)
+    {}
+    virtual ~EventFunctionImpl0 () {}
   protected:
-  	virtual void Notify (void) { 
-  		(*m_function) (); 
-      }
+    virtual void Notify (void) { 
+      (*m_function) (); 
+    }
   private:
   	F m_function;
   } *ev = new EventFunctionImpl0 (f);
-  return ev;
+  return Ptr<EventImpl> (ev, false);
 }
 EventId
-Simulator::Schedule (Time const &time, EventImpl *ev)
+Simulator::Schedule (Time const &time, const Ptr<EventImpl> &ev)
 {
   return GetPriv ()->Schedule (Now () + time, ev);
 }
 EventId
-Simulator::ScheduleNow (EventImpl *ev)
+Simulator::ScheduleNow (const Ptr<EventImpl> &ev)
 {
   return GetPriv ()->ScheduleNow (ev);
 }
 EventId
-Simulator::ScheduleDestroy (EventImpl *ev)
+Simulator::ScheduleDestroy (const Ptr<EventImpl> &ev)
 {
   return GetPriv ()->ScheduleDestroy (ev);
 }  
@@ -452,18 +466,18 @@
 
 
 void
-Simulator::Remove (EventId ev)
+Simulator::Remove (const EventId &ev)
 {
   return GetPriv ()->Remove (ev);
 }
 
 void
-Simulator::Cancel (EventId &ev)
+Simulator::Cancel (const EventId &ev)
 {
   return GetPriv ()->Cancel (ev);
 }
 bool 
-Simulator::IsExpired (EventId id)
+Simulator::IsExpired (const EventId &id)
 {
   return GetPriv ()->IsExpired (id);
 }
@@ -494,20 +508,45 @@
 static void foo4 (int, int, int, int)
 {}
 static void foo5 (int, int, int, int, int)
-{}  
+{}
+
+#if 1
+static void ber1 (int &)
+{}
+static void ber2 (int &, int &)
+{}
+static void ber3 (int &, int &, int &)
+{}
+static void ber4 (int &, int &, int &, int &)
+{}
+static void ber5 (int &, int &, int &, int &, int &)
+{}
+#endif
+
+static void cber1 (const int &)
+{}
+static void cber2 (const int &, const int &)
+{}
+static void cber3 (const int &, const int &, const int &)
+{}
+static void cber4 (const int &, const int &, const int &, const int &)
+{}
+static void cber5 (const int &, const int &, const int &, const int &, const int &)
+{}
   
 
 class SimulatorTests : public Test {
 public:
   SimulatorTests ();
   // only here for testing of Ptr<>
-  void Ref (void);
-  void Unref (void);
+  void Ref (void) const;
+  void Unref (void) const;
   virtual ~SimulatorTests ();
   virtual bool RunTests (void);
 private:
   uint64_t NowUs ();
   bool RunOneTest (void);
+  void RunTestsConst (void) const;
   void A (int a);
   void B (int b);
   void C (int c);
@@ -518,12 +557,43 @@
   void bar3 (int, int, int);
   void bar4 (int, int, int, int);
   void bar5 (int, int, int, int, int);
+  void baz1 (int &);
+  void baz2 (int &, int &);
+  void baz3 (int &, int &, int &);
+  void baz4 (int &, int &, int &, int &);
+  void baz5 (int &, int &, int &, int &, int &);
+  void cbaz1 (const int &);
+  void cbaz2 (const int &, const int &);
+  void cbaz3 (const int &, const int &, const int &);
+  void cbaz4 (const int &, const int &, const int &, const int &);
+  void cbaz5 (const int &, const int &, const int &, const int &, const int &);
+
+  void bar0c (void) const;
+  void bar1c (int) const;
+  void bar2c (int, int) const;
+  void bar3c (int, int, int) const;
+  void bar4c (int, int, int, int) const;
+  void bar5c (int, int, int, int, int) const;
+  void baz1c (int &) const;
+  void baz2c (int &, int &) const;
+  void baz3c (int &, int &, int &) const;
+  void baz4c (int &, int &, int &, int &) const;
+  void baz5c (int &, int &, int &, int &, int &) const;
+  void cbaz1c (const int &) const;
+  void cbaz2c (const int &, const int &) const;
+  void cbaz3c (const int &, const int &, const int &) const;
+  void cbaz4c (const int &, const int &, const int &, const int &) const;
+  void cbaz5c (const int &, const int &, const int &, const int &, const int &) const;
+
+  void destroy (void);
   
   bool m_b;
   bool m_a;
   bool m_c;
   bool m_d;
   EventId m_idC;
+  bool m_destroy;
+  EventId m_destroyId;
 };
 
 SimulatorTests::SimulatorTests ()
@@ -532,10 +602,10 @@
 SimulatorTests::~SimulatorTests ()
 {}
 void 
-SimulatorTests::Ref (void)
+SimulatorTests::Ref (void) const
 {}
 void 
-SimulatorTests::Unref (void)
+SimulatorTests::Unref (void) const
 {}
 uint64_t
 SimulatorTests::NowUs (void)
@@ -579,6 +649,14 @@
       m_d = true;
     }
 }
+void
+SimulatorTests::destroy (void)
+{
+  if (m_destroyId.IsExpired ())
+    {
+      m_destroy = true; 
+    }
+}
 void 
 SimulatorTests::bar0 (void)
 {}
@@ -598,10 +676,93 @@
 SimulatorTests::bar5 (int, int, int, int, int)
 {}
 
+void
+SimulatorTests::baz1 (int &)
+{}
+void
+SimulatorTests::baz2 (int &, int &)
+{}
+void
+SimulatorTests::baz3 (int &, int &, int &)
+{}
+void 
+SimulatorTests::baz4 (int &, int &, int &, int &)
+{}
+void 
+SimulatorTests::baz5 (int &, int &, int &, int &, int &)
+{}
+
+void
+SimulatorTests::cbaz1 (const int &)
+{}
+void
+SimulatorTests::cbaz2 (const int &, const int &)
+{}
+void
+SimulatorTests::cbaz3 (const int &, const int &, const int &)
+{}
+void 
+SimulatorTests::cbaz4 (const int &, const int &, const int &, const int &)
+{}
+void 
+SimulatorTests::cbaz5 (const int &, const int &, const int &, const int &, const int &)
+{}
+
+void 
+SimulatorTests::bar0c (void) const
+{}
+void 
+SimulatorTests::bar1c (int) const
+{}
+void 
+SimulatorTests::bar2c (int, int) const
+{}
+void 
+SimulatorTests::bar3c (int, int, int) const
+{}
+void 
+SimulatorTests::bar4c (int, int, int, int) const
+{}
+void 
+SimulatorTests::bar5c (int, int, int, int, int) const
+{}
+
+void
+SimulatorTests::baz1c (int &) const
+{}
+void
+SimulatorTests::baz2c (int &, int &) const
+{}
+void
+SimulatorTests::baz3c (int &, int &, int &) const
+{}
+void 
+SimulatorTests::baz4c (int &, int &, int &, int &) const
+{}
+void 
+SimulatorTests::baz5c (int &, int &, int &, int &, int &) const
+{}
+
+void
+SimulatorTests::cbaz1c (const int &) const
+{}
+void
+SimulatorTests::cbaz2c (const int &, const int &) const
+{}
+void
+SimulatorTests::cbaz3c (const int &, const int &, const int &) const
+{}
+void 
+SimulatorTests::cbaz4c (const int &, const int &, const int &, const int &) const
+{}
+void 
+SimulatorTests::cbaz5c (const int &, const int &, const int &, const int &, const int &) const
+{}
+
 bool
 SimulatorTests::RunOneTest (void)
 {
-  bool ok = true;
+  bool result = true;
   m_a = true;
   m_b = false;
   m_c = true;
@@ -611,48 +772,113 @@
   Simulator::Schedule (MicroSeconds (11), &SimulatorTests::B, this, 2);
   m_idC = Simulator::Schedule (MicroSeconds (12), &SimulatorTests::C, this, 3);
 
-  if (m_idC.IsExpired ()) 
-    {
-      ok = false;
-    }
-  if (a.IsExpired ())
-    {
-      ok = false;
-    }
+  NS_TEST_ASSERT (!m_idC.IsExpired ());
+  NS_TEST_ASSERT (!a.IsExpired ());
   Simulator::Cancel (a);
-  if (!a.IsExpired ())
-    {
-      ok = false;
-    }
+  NS_TEST_ASSERT (a.IsExpired ());
   Simulator::Run ();
+  NS_TEST_ASSERT (m_a);
+  NS_TEST_ASSERT (m_b);
+  NS_TEST_ASSERT (m_c);
+  NS_TEST_ASSERT (m_d);
+  return result;
+}
+void
+SimulatorTests::RunTestsConst (void) const
+{
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar0c, this);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar1c, this, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar2c, this, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar3c, this, 0, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar4c, this, 0, 0, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar5c, this, 0, 0, 0, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar0c, Ptr<const SimulatorTests> (this));
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar1c, Ptr<const SimulatorTests> (this), 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar2c, Ptr<const SimulatorTests> (this), 0, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar3c, Ptr<const SimulatorTests> (this), 0, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar4c, Ptr<const SimulatorTests> (this), 0, 0, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar5c, Ptr<const SimulatorTests> (this), 0, 0, 0, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::cbaz1c, this, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::cbaz2c, this, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::cbaz3c, this, 0, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::cbaz4c, this, 0, 0, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::cbaz5c, this, 0, 0, 0, 0, 0);
+  Simulator::ScheduleNow (&SimulatorTests::bar0c, this);
+  Simulator::ScheduleNow (&SimulatorTests::bar1c, this, 0);
+  Simulator::ScheduleNow (&SimulatorTests::bar2c, this, 0, 0);
+  Simulator::ScheduleNow (&SimulatorTests::bar3c, this, 0, 0, 0);
+  Simulator::ScheduleNow (&SimulatorTests::bar4c, this, 0, 0, 0, 0);
+  Simulator::ScheduleNow (&SimulatorTests::bar5c, this, 0, 0, 0, 0, 0);
+  Simulator::ScheduleNow (&SimulatorTests::cbaz1c, this, 0);
+  Simulator::ScheduleNow (&SimulatorTests::cbaz2c, this, 0, 0);
+  Simulator::ScheduleNow (&SimulatorTests::cbaz3c, this, 0, 0, 0);
+  Simulator::ScheduleNow (&SimulatorTests::cbaz4c, this, 0, 0, 0, 0);
+  Simulator::ScheduleNow (&SimulatorTests::cbaz5c, this, 0, 0, 0, 0, 0);
+  Simulator::ScheduleNow (&SimulatorTests::bar0c, Ptr<const SimulatorTests> (this));
+  Simulator::ScheduleNow (&SimulatorTests::bar1c, Ptr<const SimulatorTests> (this), 0);
+  Simulator::ScheduleNow (&SimulatorTests::bar2c, Ptr<const SimulatorTests> (this), 0, 0);
+  Simulator::ScheduleNow (&SimulatorTests::bar3c, Ptr<const SimulatorTests> (this), 0, 0, 0);
+  Simulator::ScheduleNow (&SimulatorTests::bar4c, Ptr<const SimulatorTests> (this), 0, 0, 0, 0);
+  Simulator::ScheduleNow (&SimulatorTests::bar5c, Ptr<const SimulatorTests> (this), 0, 0, 0, 0, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::bar0c, this);
+  Simulator::ScheduleDestroy (&SimulatorTests::bar1c, this, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::bar2c, this, 0, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::bar3c, this, 0, 0, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::bar4c, this, 0, 0, 0, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::bar5c, this, 0, 0, 0, 0, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::cbaz1c, this, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::cbaz2c, this, 0, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::cbaz3c, this, 0, 0, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::cbaz4c, this, 0, 0, 0, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::cbaz5c, this, 0, 0, 0, 0, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::bar0c, Ptr<const SimulatorTests> (this));
+  Simulator::ScheduleDestroy (&SimulatorTests::bar1c, Ptr<const SimulatorTests> (this), 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::bar2c, Ptr<const SimulatorTests> (this), 0, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::bar3c, Ptr<const SimulatorTests> (this), 0, 0, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::bar4c, Ptr<const SimulatorTests> (this), 0, 0, 0, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::bar5c, Ptr<const SimulatorTests> (this), 0, 0, 0, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::baz1c, this, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::baz2c, this, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::baz3c, this, 0, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::baz4c, this, 0, 0, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::baz5c, this, 0, 0, 0, 0, 0);
+  Simulator::ScheduleNow (&SimulatorTests::baz1c, this, 0);
+  Simulator::ScheduleNow (&SimulatorTests::baz2c, this, 0, 0);
+  Simulator::ScheduleNow (&SimulatorTests::baz3c, this, 0, 0, 0);
+  Simulator::ScheduleNow (&SimulatorTests::baz4c, this, 0, 0, 0, 0);
+  Simulator::ScheduleNow (&SimulatorTests::baz5c, this, 0, 0, 0, 0, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::baz1c, this, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::baz2c, this, 0, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::baz3c, this, 0, 0, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::baz4c, this, 0, 0, 0, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::baz5c, this, 0, 0, 0, 0, 0);
 
-  if (!m_a || !m_b || !m_c || !m_d) 
-    {
-      ok = false;
-    }
-  return ok;
+  Simulator::Run ();
+  Simulator::Destroy ();
 }
+
 bool 
 SimulatorTests::RunTests (void)
 {
-  bool ok = true;
+  bool result = true;
 
+  Simulator::Destroy ();
   Simulator::SetLinkedList ();
   if (!RunOneTest ()) 
     {
-      ok = false;
+      result = false;
     }
   Simulator::Destroy ();
   Simulator::SetBinaryHeap ();
   if (!RunOneTest ()) 
     {
-      ok = false;
+      result = false;
     }
   Simulator::Destroy ();
   Simulator::SetStdMap ();
   if (!RunOneTest ()) 
     {
-      ok = false;
+      result = false;
     }
   Simulator::Destroy ();
 
@@ -663,6 +889,11 @@
   Simulator::Schedule (Seconds (0.0), &foo3, 0, 0, 0);
   Simulator::Schedule (Seconds (0.0), &foo4, 0, 0, 0, 0);
   Simulator::Schedule (Seconds (0.0), &foo5, 0, 0, 0, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &cber1, 0);
+  Simulator::Schedule (Seconds (0.0), &cber2, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &cber3, 0, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &cber4, 0, 0, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &cber5, 0, 0, 0, 0, 0);
   Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar0, this);
   Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar1, this, 0);
   Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar2, this, 0, 0);
@@ -675,18 +906,33 @@
   Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar3, Ptr<SimulatorTests> (this), 0, 0, 0);
   Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar4, Ptr<SimulatorTests> (this), 0, 0, 0, 0);
   Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar5, Ptr<SimulatorTests> (this), 0, 0, 0, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::cbaz1, this, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::cbaz2, this, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::cbaz3, this, 0, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::cbaz4, this, 0, 0, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::cbaz5, this, 0, 0, 0, 0, 0);
   Simulator::ScheduleNow (&foo0);
   Simulator::ScheduleNow (&foo1, 0);
   Simulator::ScheduleNow (&foo2, 0, 0);
   Simulator::ScheduleNow (&foo3, 0, 0, 0);
   Simulator::ScheduleNow (&foo4, 0, 0, 0, 0);
   Simulator::ScheduleNow (&foo5, 0, 0, 0, 0, 0);
+  Simulator::ScheduleNow (&cber1, 0);
+  Simulator::ScheduleNow (&cber2, 0, 0);
+  Simulator::ScheduleNow (&cber3, 0, 0, 0);
+  Simulator::ScheduleNow (&cber4, 0, 0, 0, 0);
+  Simulator::ScheduleNow (&cber5, 0, 0, 0, 0, 0);
   Simulator::ScheduleNow (&SimulatorTests::bar0, this);
   Simulator::ScheduleNow (&SimulatorTests::bar1, this, 0);
   Simulator::ScheduleNow (&SimulatorTests::bar2, this, 0, 0);
   Simulator::ScheduleNow (&SimulatorTests::bar3, this, 0, 0, 0);
   Simulator::ScheduleNow (&SimulatorTests::bar4, this, 0, 0, 0, 0);
   Simulator::ScheduleNow (&SimulatorTests::bar5, this, 0, 0, 0, 0, 0);
+  Simulator::ScheduleNow (&SimulatorTests::cbaz1, this, 0);
+  Simulator::ScheduleNow (&SimulatorTests::cbaz2, this, 0, 0);
+  Simulator::ScheduleNow (&SimulatorTests::cbaz3, this, 0, 0, 0);
+  Simulator::ScheduleNow (&SimulatorTests::cbaz4, this, 0, 0, 0, 0);
+  Simulator::ScheduleNow (&SimulatorTests::cbaz5, this, 0, 0, 0, 0, 0);
   Simulator::ScheduleNow (&SimulatorTests::bar0, Ptr<SimulatorTests> (this));
   Simulator::ScheduleNow (&SimulatorTests::bar1, Ptr<SimulatorTests> (this), 0);
   Simulator::ScheduleNow (&SimulatorTests::bar2, Ptr<SimulatorTests> (this), 0, 0);
@@ -699,12 +945,22 @@
   Simulator::ScheduleDestroy (&foo3, 0, 0, 0);
   Simulator::ScheduleDestroy (&foo4, 0, 0, 0, 0);
   Simulator::ScheduleDestroy (&foo5, 0, 0, 0, 0, 0);
+  Simulator::ScheduleDestroy (&cber1, 0);
+  Simulator::ScheduleDestroy (&cber2, 0, 0);
+  Simulator::ScheduleDestroy (&cber3, 0, 0, 0);
+  Simulator::ScheduleDestroy (&cber4, 0, 0, 0, 0);
+  Simulator::ScheduleDestroy (&cber5, 0, 0, 0, 0, 0);
   Simulator::ScheduleDestroy (&SimulatorTests::bar0, this);
   Simulator::ScheduleDestroy (&SimulatorTests::bar1, this, 0);
   Simulator::ScheduleDestroy (&SimulatorTests::bar2, this, 0, 0);
   Simulator::ScheduleDestroy (&SimulatorTests::bar3, this, 0, 0, 0);
   Simulator::ScheduleDestroy (&SimulatorTests::bar4, this, 0, 0, 0, 0);
   Simulator::ScheduleDestroy (&SimulatorTests::bar5, this, 0, 0, 0, 0, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::cbaz1, this, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::cbaz2, this, 0, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::cbaz3, this, 0, 0, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::cbaz4, this, 0, 0, 0, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::cbaz5, this, 0, 0, 0, 0, 0);
   Simulator::ScheduleDestroy (&SimulatorTests::bar0, Ptr<SimulatorTests> (this));
   Simulator::ScheduleDestroy (&SimulatorTests::bar1, Ptr<SimulatorTests> (this), 0);
   Simulator::ScheduleDestroy (&SimulatorTests::bar2, Ptr<SimulatorTests> (this), 0, 0);
@@ -712,13 +968,67 @@
   Simulator::ScheduleDestroy (&SimulatorTests::bar4, Ptr<SimulatorTests> (this), 0, 0, 0, 0);
   Simulator::ScheduleDestroy (&SimulatorTests::bar5, Ptr<SimulatorTests> (this), 0, 0, 0, 0, 0);
 
+
+  // the code below does not compile, as expected.
+  //Simulator::Schedule (Seconds (0.0), &cber1, 0.0);
+
+#if 1
+  Simulator::Schedule (Seconds (0.0), &ber1, 0);
+  Simulator::Schedule (Seconds (0.0), &ber2, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &ber3, 0, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &ber4, 0, 0, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &ber5, 0, 0, 0, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::baz1, this, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::baz2, this, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::baz3, this, 0, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::baz4, this, 0, 0, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::baz5, this, 0, 0, 0, 0, 0);
+  Simulator::ScheduleNow (&ber1, 0);
+  Simulator::ScheduleNow (&ber2, 0, 0);
+  Simulator::ScheduleNow (&ber3, 0, 0, 0);
+  Simulator::ScheduleNow (&ber4, 0, 0, 0, 0);
+  Simulator::ScheduleNow (&ber5, 0, 0, 0, 0, 0);
+  Simulator::ScheduleNow (&SimulatorTests::baz1, this, 0);
+  Simulator::ScheduleNow (&SimulatorTests::baz2, this, 0, 0);
+  Simulator::ScheduleNow (&SimulatorTests::baz3, this, 0, 0, 0);
+  Simulator::ScheduleNow (&SimulatorTests::baz4, this, 0, 0, 0, 0);
+  Simulator::ScheduleNow (&SimulatorTests::baz5, this, 0, 0, 0, 0, 0);
+  Simulator::ScheduleDestroy (&ber1, 0);
+  Simulator::ScheduleDestroy (&ber2, 0, 0);
+  Simulator::ScheduleDestroy (&ber3, 0, 0, 0);
+  Simulator::ScheduleDestroy (&ber4, 0, 0, 0, 0);
+  Simulator::ScheduleDestroy (&ber5, 0, 0, 0, 0, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::baz1, this, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::baz2, this, 0, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::baz3, this, 0, 0, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::baz4, this, 0, 0, 0, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::baz5, this, 0, 0, 0, 0, 0);
+#endif
+
+  RunTestsConst ();
+
   EventId nowId = Simulator::ScheduleNow (&foo0);
-  EventId destroyId = Simulator::ScheduleDestroy (&foo0);
+  m_destroyId = Simulator::ScheduleDestroy (&SimulatorTests::destroy, this);
+  NS_TEST_ASSERT (!m_destroyId.IsExpired ());
+
+  Simulator::Run ();
+  m_destroy = false;
+  Simulator::Destroy ();
+  NS_TEST_ASSERT (m_destroy);
+
+  EventId anId = Simulator::ScheduleNow (&foo0);
+  EventId anotherId = anId;
+  NS_TEST_ASSERT (!(anId.IsExpired () || anotherId.IsExpired ()));
+
+  Simulator::Remove (anId);
+  NS_TEST_ASSERT (anId.IsExpired ());
+  NS_TEST_ASSERT (anotherId.IsExpired ());
 
   Simulator::Run ();
   Simulator::Destroy ();
+  
 
-  return ok;
+  return result;
 }
 
 SimulatorTests gSimulatorTests;
--- a/src/simulator/simulator.h	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/simulator/simulator.h	Fri Sep 28 11:59:46 2007 +0100
@@ -26,6 +26,7 @@
 #include "event-id.h"
 #include "event-impl.h"
 #include "nstime.h"
+#include "ns3/type-traits.h"
 
 namespace ns3 {
 
@@ -162,8 +163,8 @@
    * @param obj the object on which to invoke the member method
    * @returns an id for the scheduled event.
    */
-  template <typename T, typename OBJ>
-  static EventId Schedule (Time const &time, void (T::*mem_ptr) (void), OBJ obj);
+  template <typename MEM, typename OBJ>
+  static EventId Schedule (Time const &time, MEM mem_ptr, OBJ obj);
   /**
    * @param time the relative expiration time of the event.
    * @param mem_ptr member method pointer to invoke
@@ -171,8 +172,8 @@
    * @param a1 the first argument to pass to the invoked method
    * @returns an id for the scheduled event.
    */
-  template <typename T, typename OBJ, typename T1>
-  static EventId Schedule (Time const &time, void (T::*mem_ptr) (T1), OBJ obj, T1 a1);
+  template <typename MEM, typename OBJ, typename T1>
+  static EventId Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1);
   /**
    * @param time the relative expiration time of the event.
    * @param mem_ptr member method pointer to invoke
@@ -181,8 +182,8 @@
    * @param a2 the second argument to pass to the invoked method
    * @returns an id for the scheduled event.
    */
-  template <typename T, typename OBJ, typename T1, typename T2>
-  static EventId Schedule (Time const &time, void (T::*mem_ptr) (T1,T2), OBJ obj, T1 a1, T2 a2);
+  template <typename MEM, typename OBJ, typename T1, typename T2>
+  static EventId Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1, T2 a2);
   /**
    * @param time the relative expiration time of the event.
    * @param mem_ptr member method pointer to invoke
@@ -192,8 +193,9 @@
    * @param a3 the third argument to pass to the invoked method
    * @returns an id for the scheduled event.
    */
-  template <typename T, typename OBJ, typename T1, typename T2, typename T3>
-  static EventId Schedule (Time const &time, void (T::*mem_ptr) (T1,T2,T3), OBJ obj, T1 a1, T2 a2, T3 a3);
+  template <typename MEM, typename OBJ, 
+            typename T1, typename T2, typename T3>
+  static EventId Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3);
   /**
    * @param time the relative expiration time of the event.
    * @param mem_ptr member method pointer to invoke
@@ -204,8 +206,9 @@
    * @param a4 the fourth argument to pass to the invoked method
    * @returns an id for the scheduled event.
    */
-  template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4>
-  static EventId Schedule (Time const &time, void (T::*mem_ptr) (T1,T2,T3,T4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4);
+  template <typename MEM, typename OBJ, 
+            typename T1, typename T2, typename T3, typename T4>
+  static EventId Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4);
   /**
    * @param time the relative expiration time of the event.
    * @param mem_ptr member method pointer to invoke
@@ -217,8 +220,9 @@
    * @param a5 the fifth argument to pass to the invoked method
    * @returns an id for the scheduled event.
    */
-  template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4, typename T5>
-  static EventId Schedule (Time const &time, void (T::*mem_ptr) (T1,T2,T3,T4,T5), OBJ obj, 
+  template <typename MEM, typename OBJ, 
+            typename T1, typename T2, typename T3, typename T4, typename T5>
+  static EventId Schedule (Time const &time, MEM mem_ptr, OBJ obj, 
                            T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
   /**
    * @param time the relative expiration time of the event.
@@ -232,8 +236,8 @@
    * @param a1 the first argument to pass to the function to invoke
    * @returns an id for the scheduled event.
    */
-  template <typename T1>
-  static EventId Schedule (Time const &time, void (*f) (T1), T1 a1);
+  template <typename U1, typename T1>
+  static EventId Schedule (Time const &time, void (*f) (U1), T1 a1);
   /**
    * @param time the relative expiration time of the event.
    * @param f the function to invoke
@@ -241,8 +245,8 @@
    * @param a2 the second argument to pass to the function to invoke
    * @returns an id for the scheduled event.
    */
-  template <typename T1, typename T2>
-  static EventId Schedule (Time const &time, void (*f) (T1,T2), T1 a1, T2 a2);
+  template <typename U1, typename U2, typename T1, typename T2>
+  static EventId Schedule (Time const &time, void (*f) (U1,U2), T1 a1, T2 a2);
   /**
    * @param time the relative expiration time of the event.
    * @param f the function to invoke
@@ -251,8 +255,8 @@
    * @param a3 the third argument to pass to the function to invoke
    * @returns an id for the scheduled event.
    */
-  template <typename T1, typename T2, typename T3>
-  static EventId Schedule (Time const &time, void (*f) (T1,T2,T3), T1 a1, T2 a2, T3 a3);
+  template <typename U1, typename U2, typename U3, typename T1, typename T2, typename T3>
+  static EventId Schedule (Time const &time, void (*f) (U1,U2,U3), T1 a1, T2 a2, T3 a3);
   /**
    * @param time the relative expiration time of the event.
    * @param f the function to invoke
@@ -262,8 +266,9 @@
    * @param a4 the fourth argument to pass to the function to invoke
    * @returns an id for the scheduled event.
    */
-  template <typename T1, typename T2, typename T3, typename T4>
-  static EventId Schedule (Time const &time, void (*f) (T1,T2,T3,T4), T1 a1, T2 a2, T3 a3, T4 a4);
+  template <typename U1, typename U2, typename U3, typename U4, 
+            typename T1, typename T2, typename T3, typename T4>
+  static EventId Schedule (Time const &time, void (*f) (U1,U2,U3,U4), T1 a1, T2 a2, T3 a3, T4 a4);
   /**
    * @param time the relative expiration time of the event.
    * @param f the function to invoke
@@ -274,8 +279,9 @@
    * @param a5 the fifth argument to pass to the function to invoke
    * @returns an id for the scheduled event.
    */
-  template <typename T1, typename T2, typename T3, typename T4, typename T5>
-  static EventId Schedule (Time const &time, void (*f) (T1,T2,T3,T4,T5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
+  template <typename U1, typename U2, typename U3, typename U4, typename U5,
+            typename T1, typename T2, typename T3, typename T4, typename T5>
+  static EventId Schedule (Time const &time, void (*f) (U1,U2,U3,U4,U5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
 
 
   /**
@@ -286,23 +292,25 @@
    * @param mem_ptr member method pointer to invoke
    * @param obj the object on which to invoke the member method
    */
-  template <typename T, typename OBJ>
-  static EventId ScheduleNow (void (T::*mem_ptr) (void), OBJ obj);
+  template <typename MEM, typename OBJ>
+  static EventId ScheduleNow (MEM mem_ptr, OBJ obj);
   /**
    * @param mem_ptr member method pointer to invoke
    * @param obj the object on which to invoke the member method
    * @param a1 the first argument to pass to the invoked method
    */
-  template <typename T, typename OBJ, typename T1>
-  static EventId ScheduleNow (void (T::*mem_ptr) (T1), OBJ obj, T1 a1);
+  template <typename MEM, typename OBJ, 
+            typename T1>
+  static EventId ScheduleNow (MEM mem_ptr, OBJ obj, T1 a1);
   /**
    * @param mem_ptr member method pointer to invoke
    * @param obj the object on which to invoke the member method
    * @param a1 the first argument to pass to the invoked method
    * @param a2 the second argument to pass to the invoked method
    */
-  template <typename T, typename OBJ, typename T1, typename T2>
-  static EventId ScheduleNow (void (T::*mem_ptr) (T1,T2), OBJ obj, T1 a1, T2 a2);
+  template <typename MEM, typename OBJ, 
+            typename T1, typename T2>
+  static EventId ScheduleNow (MEM mem_ptr, OBJ obj, T1 a1, T2 a2);
   /**
    * @param mem_ptr member method pointer to invoke
    * @param obj the object on which to invoke the member method
@@ -310,8 +318,9 @@
    * @param a2 the second argument to pass to the invoked method
    * @param a3 the third argument to pass to the invoked method
    */
-  template <typename T, typename OBJ, typename T1, typename T2, typename T3>
-  static EventId ScheduleNow (void (T::*mem_ptr) (T1,T2,T3), OBJ obj, T1 a1, T2 a2, T3 a3);
+  template <typename MEM, typename OBJ, 
+            typename T1, typename T2, typename T3>
+  static EventId ScheduleNow (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3);
   /**
    * @param mem_ptr member method pointer to invoke
    * @param obj the object on which to invoke the member method
@@ -320,9 +329,10 @@
    * @param a3 the third argument to pass to the invoked method
    * @param a4 the fourth argument to pass to the invoked method
    */
-  template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4>
-  static EventId ScheduleNow (void (T::*mem_ptr) (T1,T2,T3,T4), OBJ obj, 
-                           T1 a1, T2 a2, T3 a3, T4 a4);
+  template <typename MEM, typename OBJ, 
+            typename T1, typename T2, typename T3, typename T4>
+  static EventId ScheduleNow (MEM mem_ptr, OBJ obj, 
+                              T1 a1, T2 a2, T3 a3, T4 a4);
   /**
    * @param mem_ptr member method pointer to invoke
    * @param obj the object on which to invoke the member method
@@ -332,9 +342,10 @@
    * @param a4 the fourth argument to pass to the invoked method
    * @param a5 the fifth argument to pass to the invoked method
    */
-  template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4, typename T5>
-  static EventId ScheduleNow (void (T::*mem_ptr) (T1,T2,T3,T4,T5), OBJ obj, 
-                           T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
+  template <typename MEM, typename OBJ, 
+            typename T1, typename T2, typename T3, typename T4, typename T5>
+  static EventId ScheduleNow (MEM mem_ptr, OBJ obj, 
+                              T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
   /**
    * @param f the function to invoke
    */
@@ -343,23 +354,26 @@
    * @param f the function to invoke
    * @param a1 the first argument to pass to the function to invoke
    */
-  template <typename T1>
-  static EventId ScheduleNow (void (*f) (T1), T1 a1);
+  template <typename U1,
+            typename T1>
+  static EventId ScheduleNow (void (*f) (U1), T1 a1);
   /**
    * @param f the function to invoke
    * @param a1 the first argument to pass to the function to invoke
    * @param a2 the second argument to pass to the function to invoke
    */
-  template <typename T1, typename T2>
-  static EventId ScheduleNow (void (*f) (T1,T2), T1 a1, T2 a2);
+  template <typename U1, typename U2,
+            typename T1, typename T2>
+  static EventId ScheduleNow (void (*f) (U1,U2), T1 a1, T2 a2);
   /**
    * @param f the function to invoke
    * @param a1 the first argument to pass to the function to invoke
    * @param a2 the second argument to pass to the function to invoke
    * @param a3 the third argument to pass to the function to invoke
    */
-  template <typename T1, typename T2, typename T3>
-  static EventId ScheduleNow (void (*f) (T1,T2,T3), T1 a1, T2 a2, T3 a3);
+  template <typename U1, typename U2, typename U3,
+            typename T1, typename T2, typename T3>
+  static EventId ScheduleNow (void (*f) (U1,U2,U3), T1 a1, T2 a2, T3 a3);
   /**
    * @param f the function to invoke
    * @param a1 the first argument to pass to the function to invoke
@@ -367,8 +381,9 @@
    * @param a3 the third argument to pass to the function to invoke
    * @param a4 the fourth argument to pass to the function to invoke
    */
-  template <typename T1, typename T2, typename T3, typename T4>
-  static EventId ScheduleNow (void (*f) (T1,T2,T3,T4), T1 a1, T2 a2, T3 a3, T4 a4);
+  template <typename U1, typename U2, typename U3, typename U4,
+            typename T1, typename T2, typename T3, typename T4>
+  static EventId ScheduleNow (void (*f) (U1,U2,U3,U4), T1 a1, T2 a2, T3 a3, T4 a4);
   /**
    * @param f the function to invoke
    * @param a1 the first argument to pass to the function to invoke
@@ -377,8 +392,9 @@
    * @param a4 the fourth argument to pass to the function to invoke
    * @param a5 the fifth argument to pass to the function to invoke
    */
-  template <typename T1, typename T2, typename T3, typename T4, typename T5>
-  static EventId ScheduleNow (void (*f) (T1,T2,T3,T4,T5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
+  template <typename U1, typename U2, typename U3, typename U4, typename U5,
+            typename T1, typename T2, typename T3, typename T4, typename T5>
+  static EventId ScheduleNow (void (*f) (U1,U2,U3,U4,U5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
 
 
   /**
@@ -390,23 +406,25 @@
    * @param mem_ptr member method pointer to invoke
    * @param obj the object on which to invoke the member method
    */
-  template <typename T, typename OBJ>
-  static EventId ScheduleDestroy (void (T::*mem_ptr) (void), OBJ obj);
+  template <typename MEM, typename OBJ>
+  static EventId ScheduleDestroy (MEM mem_ptr, OBJ obj);
   /**
    * @param mem_ptr member method pointer to invoke
    * @param obj the object on which to invoke the member method
    * @param a1 the first argument to pass to the invoked method
    */
-  template <typename T, typename OBJ, typename T1>
-  static EventId ScheduleDestroy (void (T::*mem_ptr) (T1), OBJ obj, T1 a1);
+  template <typename MEM, typename OBJ, 
+            typename T1>
+  static EventId ScheduleDestroy (MEM mem_ptr, OBJ obj, T1 a1);
   /**
    * @param mem_ptr member method pointer to invoke
    * @param obj the object on which to invoke the member method
    * @param a1 the first argument to pass to the invoked method
    * @param a2 the second argument to pass to the invoked method
    */
-  template <typename T, typename OBJ, typename T1, typename T2>
-  static EventId ScheduleDestroy (void (T::*mem_ptr) (T1,T2), OBJ obj, T1 a1, T2 a2);
+  template <typename MEM, typename OBJ,
+            typename T1, typename T2>
+  static EventId ScheduleDestroy (MEM mem_ptr, OBJ obj, T1 a1, T2 a2);
   /**
    * @param mem_ptr member method pointer to invoke
    * @param obj the object on which to invoke the member method
@@ -414,8 +432,9 @@
    * @param a2 the second argument to pass to the invoked method
    * @param a3 the third argument to pass to the invoked method
    */
-  template <typename T, typename OBJ, typename T1, typename T2, typename T3>
-  static EventId ScheduleDestroy (void (T::*mem_ptr) (T1,T2,T3), OBJ obj, T1 a1, T2 a2, T3 a3);
+  template <typename MEM, typename OBJ, 
+            typename T1, typename T2, typename T3>
+  static EventId ScheduleDestroy (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3);
   /**
    * @param mem_ptr member method pointer to invoke
    * @param obj the object on which to invoke the member method
@@ -424,9 +443,10 @@
    * @param a3 the third argument to pass to the invoked method
    * @param a4 the fourth argument to pass to the invoked method
    */
-  template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4>
-  static EventId ScheduleDestroy (void (T::*mem_ptr) (T1,T2,T3,T4), OBJ obj, 
-                               T1 a1, T2 a2, T3 a3, T4 a4);
+  template <typename MEM, typename OBJ, 
+            typename T1, typename T2, typename T3, typename T4>
+  static EventId ScheduleDestroy (MEM mem_ptr, OBJ obj, 
+                                  T1 a1, T2 a2, T3 a3, T4 a4);
   /**
    * @param mem_ptr member method pointer to invoke
    * @param obj the object on which to invoke the member method
@@ -436,9 +456,10 @@
    * @param a4 the fourth argument to pass to the invoked method
    * @param a5 the fifth argument to pass to the invoked method
    */
-  template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4, typename T5>
-  static EventId ScheduleDestroy (void (T::*mem_ptr) (T1,T2,T3,T4,T5), OBJ obj, 
-                               T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
+  template <typename MEM, typename OBJ, 
+            typename T1, typename T2, typename T3, typename T4, typename T5>
+  static EventId ScheduleDestroy (MEM mem_ptr, OBJ obj, 
+                                  T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
   /**
    * @param f the function to invoke
    */
@@ -447,23 +468,26 @@
    * @param f the function to invoke
    * @param a1 the first argument to pass to the function to invoke
    */
-  template <typename T1>
-  static EventId ScheduleDestroy (void (*f) (T1), T1 a1);
+  template <typename U1,
+            typename T1>
+  static EventId ScheduleDestroy (void (*f) (U1), T1 a1);
   /**
    * @param f the function to invoke
    * @param a1 the first argument to pass to the function to invoke
    * @param a2 the second argument to pass to the function to invoke
    */
-  template <typename T1, typename T2>
-  static EventId ScheduleDestroy (void (*f) (T1,T2), T1 a1, T2 a2);
+  template <typename U1, typename U2,
+            typename T1, typename T2>
+  static EventId ScheduleDestroy (void (*f) (U1,U2), T1 a1, T2 a2);
   /**
    * @param f the function to invoke
    * @param a1 the first argument to pass to the function to invoke
    * @param a2 the second argument to pass to the function to invoke
    * @param a3 the third argument to pass to the function to invoke
    */
-  template <typename T1, typename T2, typename T3>
-  static EventId ScheduleDestroy (void (*f) (T1,T2,T3), T1 a1, T2 a2, T3 a3);
+  template <typename U1, typename U2, typename U3,
+            typename T1, typename T2, typename T3>
+  static EventId ScheduleDestroy (void (*f) (U1,U2,U3), T1 a1, T2 a2, T3 a3);
   /**
    * @param f the function to invoke
    * @param a1 the first argument to pass to the function to invoke
@@ -471,8 +495,9 @@
    * @param a3 the third argument to pass to the function to invoke
    * @param a4 the fourth argument to pass to the function to invoke
    */
-  template <typename T1, typename T2, typename T3, typename T4>
-  static EventId ScheduleDestroy (void (*f) (T1,T2,T3,T4), T1 a1, T2 a2, T3 a3, T4 a4);
+  template <typename U1, typename U2, typename U3, typename U4,
+            typename T1, typename T2, typename T3, typename T4>
+  static EventId ScheduleDestroy (void (*f) (U1,U2,U3,U4), T1 a1, T2 a2, T3 a3, T4 a4);
   /**
    * @param f the function to invoke
    * @param a1 the first argument to pass to the function to invoke
@@ -481,8 +506,9 @@
    * @param a4 the fourth argument to pass to the function to invoke
    * @param a5 the fifth argument to pass to the function to invoke
    */
-  template <typename T1, typename T2, typename T3, typename T4, typename T5>
-  static EventId ScheduleDestroy (void (*f) (T1,T2,T3,T4,T5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
+  template <typename U1, typename U2, typename U3, typename U4, typename U5,
+            typename T1, typename T2, typename T3, typename T4, typename T5>
+  static EventId ScheduleDestroy (void (*f) (U1,U2,U3,U4,U5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
 
   /**
    * Remove an event from the event list. 
@@ -495,7 +521,7 @@
    *
    * @param id the event to remove from the list of scheduled events.
    */
-  static void Remove (EventId id);
+  static void Remove (const EventId &id);
   /**
    * Set the cancel bit on this event: the event's associated function
    * will not be invoked when it expires. 
@@ -508,7 +534,7 @@
    * 
    * @param id the event to cancel
    */
-  static void Cancel (EventId &id);
+  static void Cancel (const EventId &id);
   /**
    * This method has O(1) complexity.
    * Note that it is not possible to test for the expiration of
@@ -521,7 +547,7 @@
    * @param id the event to test for expiration
    * @returns true if the event has expired, false otherwise.
    */
-  static bool IsExpired (EventId id);
+  static bool IsExpired (const EventId &id);
   /**
    * Return the "current simulation time".
    */
@@ -529,35 +555,46 @@
 private:
   Simulator ();
   ~Simulator ();
-  template <typename T, typename OBJ>
-  static EventImpl *MakeEvent (void (T::*mem_ptr) (void), OBJ obj);
-  template <typename T, typename OBJ, typename T1>
-  static EventImpl *MakeEvent (void (T::*mem_ptr) (T1), OBJ obj, T1 a1);
-  template <typename T, typename OBJ, typename T1, typename T2>
-  static EventImpl *MakeEvent (void (T::*mem_ptr) (T1,T2), OBJ obj, T1 a1, T2 a2);
-  template <typename T, typename OBJ, typename T1, typename T2, typename T3>
-  static EventImpl *MakeEvent (void (T::*mem_ptr) (T1,T2,T3), OBJ obj, T1 a1, T2 a2, T3 a3);
-  template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4>
-  static EventImpl *MakeEvent (void (T::*mem_ptr) (T1,T2,T3,T4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4);
-  template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4, typename T5>
-  static EventImpl *MakeEvent (void (T::*mem_ptr) (T1,T2,T3,T4,T5), OBJ obj, 
-                               T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
-  static EventImpl *MakeEvent (void (*f) (void));
-  template <typename T1>
-  static EventImpl *MakeEvent (void (*f) (T1), T1 a1);
-  template <typename T1, typename T2>
-  static EventImpl *MakeEvent (void (*f) (T1,T2), T1 a1, T2 a2);
-  template <typename T1, typename T2, typename T3>
-  static EventImpl *MakeEvent (void (*f) (T1,T2,T3), T1 a1, T2 a2, T3 a3);
-  template <typename T1, typename T2, typename T3, typename T4>
-  static EventImpl *MakeEvent (void (*f) (T1,T2,T3,T4), T1 a1, T2 a2, T3 a3, T4 a4);
-  template <typename T1, typename T2, typename T3, typename T4, typename T5>
-  static EventImpl *MakeEvent (void (*f) (T1,T2,T3,T4,T5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
+
+  template <typename MEM, typename OBJ>
+  static Ptr<EventImpl> MakeEvent (MEM mem_ptr, OBJ obj);
+  template <typename MEM, typename OBJ, 
+            typename T1>
+  static Ptr<EventImpl> MakeEvent (MEM mem_ptr, OBJ obj, T1 a1);
+  template <typename MEM, typename OBJ, 
+            typename T1, typename T2>
+  static Ptr<EventImpl> MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2);
+  template <typename MEM, typename OBJ, 
+            typename T1, typename T2, typename T3>
+  static Ptr<EventImpl> MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3);
+  template <typename MEM, typename OBJ, 
+            typename T1, typename T2, typename T3, typename T4>
+  static Ptr<EventImpl> MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4);
+  template <typename MEM, typename OBJ, 
+            typename T1, typename T2, typename T3, typename T4, typename T5>
+  static Ptr<EventImpl> MakeEvent (MEM mem_ptr, OBJ obj, 
+                                   T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
+  static Ptr<EventImpl> MakeEvent (void (*f) (void));
+  template <typename U1, 
+            typename T1>
+  static Ptr<EventImpl> MakeEvent (void (*f) (U1), T1 a1);
+  template <typename U1, typename U2, 
+            typename T1, typename T2>
+  static Ptr<EventImpl> MakeEvent (void (*f) (U1,U2), T1 a1, T2 a2);
+  template <typename U1, typename U2, typename U3,
+            typename T1, typename T2, typename T3>
+  static Ptr<EventImpl> MakeEvent (void (*f) (U1,U2,U3), T1 a1, T2 a2, T3 a3);
+  template <typename U1, typename U2, typename U3, typename U4,
+            typename T1, typename T2, typename T3, typename T4>
+  static Ptr<EventImpl> MakeEvent (void (*f) (U1,U2,U3,U4), T1 a1, T2 a2, T3 a3, T4 a4);
+  template <typename U1, typename U2, typename U3, typename U4, typename U5,
+            typename T1, typename T2, typename T3, typename T4, typename T5>
+  static Ptr<EventImpl> MakeEvent (void (*f) (U1,U2,U3,U4,U5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
 
   static SimulatorPrivate *GetPriv (void);
-  static EventId Schedule (Time const &time, EventImpl *event);
-  static EventId ScheduleDestroy (EventImpl *event);
-  static EventId ScheduleNow (EventImpl *event);
+  static EventId Schedule (Time const &time, const Ptr<EventImpl> &event);
+  static EventId ScheduleDestroy (const Ptr<EventImpl> &event);
+  static EventId ScheduleNow (const Ptr<EventImpl> &event);
   static SimulatorPrivate *m_priv;
 };
 
@@ -584,47 +621,46 @@
 namespace ns3 {
 
 template <typename T>
-struct EventMemberImplTraits;
+struct EventMemberImplObjTraits;
 
 template <typename T>
-struct EventMemberImplTraits<T *>
+struct EventMemberImplObjTraits<T *>
 {
   static T &GetReference (T *p) {
     return *p;
   }
 };
 
-template <typename T, typename OBJ>
-EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (void), OBJ obj) 
+template <typename MEM, typename OBJ>
+Ptr<EventImpl> Simulator::MakeEvent (MEM mem_ptr, OBJ obj) 
 {
   // zero argument version
   class EventMemberImpl0 : public EventImpl {
   public:
-    typedef void (T::*F)(void);
-    EventMemberImpl0 (OBJ obj, F function) 
+    EventMemberImpl0 (OBJ obj, MEM function) 
       : m_obj (obj), 
         m_function (function)
     {}
     virtual ~EventMemberImpl0 () {}
   private:
     virtual void Notify (void) { 
-      (EventMemberImplTraits<OBJ>::GetReference (m_obj).*m_function) (); 
+      (EventMemberImplObjTraits<OBJ>::GetReference (m_obj).*m_function) (); 
     }
     OBJ m_obj;
-    F m_function;
-  } *ev = new EventMemberImpl0 (obj, mem_ptr);
-  return ev;
+    MEM m_function;
+  } * ev = new EventMemberImpl0 (obj, mem_ptr);
+  return Ptr<EventImpl> (ev, false);
 }
 
 
-template <typename T, typename OBJ, typename T1>
-EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (T1), OBJ obj, T1 a1) 
+template <typename MEM, typename OBJ, 
+          typename T1>
+Ptr<EventImpl> Simulator::MakeEvent (MEM mem_ptr, OBJ obj, T1 a1)
 {
   // one argument version
   class EventMemberImpl1 : public EventImpl {
   public:
-    typedef void (T::*F)(T1);
-    EventMemberImpl1 (OBJ obj, F function, T1 a1) 
+    EventMemberImpl1 (OBJ obj, MEM function, T1 a1) 
       : m_obj (obj), 
         m_function (function),
         m_a1 (a1)
@@ -633,24 +669,23 @@
     virtual ~EventMemberImpl1 () {}
   private:
     virtual void Notify (void) { 
-      (EventMemberImplTraits<OBJ>::GetReference (m_obj).*m_function) (m_a1);
+      (EventMemberImplObjTraits<OBJ>::GetReference (m_obj).*m_function) (m_a1);
     }
     OBJ m_obj;
-    F m_function;
-    T1 m_a1;
+    MEM m_function;
+    typename TypeTraits<T1>::ReferencedType m_a1;
   } *ev = new EventMemberImpl1 (obj, mem_ptr, a1);
-  return ev;
+  return Ptr<EventImpl> (ev, false);
 }
 
-template <typename T, typename OBJ, typename T1, typename T2>
-EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (T1,T2), OBJ obj, T1 a1, T2 a2) 
+template <typename MEM, typename OBJ, 
+          typename T1, typename T2>
+Ptr<EventImpl> Simulator::MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2) 
 {
   // two argument version
   class EventMemberImpl2 : public EventImpl {
   public:
-    typedef void (T::*F)(T1, T2);
-      
-    EventMemberImpl2 (OBJ obj, F function, T1 a1, T2 a2) 
+    EventMemberImpl2 (OBJ obj, MEM function, T1 a1, T2 a2) 
       : m_obj (obj), 
         m_function (function),
         m_a1 (a1),
@@ -660,25 +695,24 @@
     virtual ~EventMemberImpl2 () {}
   private:
     virtual void Notify (void) { 
-      (EventMemberImplTraits<OBJ>::GetReference (m_obj).*m_function) (m_a1, m_a2);
+      (EventMemberImplObjTraits<OBJ>::GetReference (m_obj).*m_function) (m_a1, m_a2);
     }
     OBJ m_obj;
-    F m_function;
-    T1 m_a1;
-    T2 m_a2;
+    MEM m_function;
+    typename TypeTraits<T1>::ReferencedType m_a1;
+    typename TypeTraits<T2>::ReferencedType m_a2;
   } *ev = new EventMemberImpl2 (obj, mem_ptr, a1, a2);
-  return ev;
+  return Ptr<EventImpl> (ev, false);
 }
 
-template <typename T, typename OBJ, typename T1, typename T2, typename T3>
-EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (T1,T2,T3), OBJ obj, T1 a1, T2 a2, T3 a3) 
+template <typename MEM, typename OBJ, 
+          typename T1, typename T2, typename T3>
+Ptr<EventImpl> Simulator::MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3) 
 {
   // three argument version
   class EventMemberImpl3 : public EventImpl {
   public:
-    typedef void (T::*F)(T1, T2, T3);
-      
-    EventMemberImpl3 (OBJ obj, F function, T1 a1, T2 a2, T3 a3) 
+    EventMemberImpl3 (OBJ obj, MEM function, T1 a1, T2 a2, T3 a3) 
       : m_obj (obj), 
         m_function (function),
         m_a1 (a1),
@@ -689,26 +723,25 @@
     virtual ~EventMemberImpl3 () {}
   private:
     virtual void Notify (void) { 
-      (EventMemberImplTraits<OBJ>::GetReference (m_obj).*m_function) (m_a1, m_a2, m_a3);
+      (EventMemberImplObjTraits<OBJ>::GetReference (m_obj).*m_function) (m_a1, m_a2, m_a3);
     }
     OBJ m_obj;
-    F m_function;
-    T1 m_a1;
-    T2 m_a2;
-    T3 m_a3;
+    MEM m_function;
+    typename TypeTraits<T1>::ReferencedType m_a1;
+    typename TypeTraits<T2>::ReferencedType m_a2;
+    typename TypeTraits<T3>::ReferencedType m_a3;
   } *ev = new EventMemberImpl3 (obj, mem_ptr, a1, a2, a3);
-  return ev;
+  return Ptr<EventImpl> (ev, false);
 }
 
-template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4>
-EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (T1,T2,T3,T4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4) 
+template <typename MEM, typename OBJ, 
+          typename T1, typename T2, typename T3, typename T4>
+Ptr<EventImpl> Simulator::MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4) 
 {
   // four argument version
   class EventMemberImpl4 : public EventImpl {
   public:
-    typedef void (T::*F)(T1, T2, T3, T4);
-          
-    EventMemberImpl4 (OBJ obj, F function, T1 a1, T2 a2, T3 a3, T4 a4) 
+    EventMemberImpl4 (OBJ obj, MEM function, T1 a1, T2 a2, T3 a3, T4 a4) 
       : m_obj (obj), 
         m_function (function),
         m_a1 (a1),
@@ -720,28 +753,27 @@
     virtual ~EventMemberImpl4 () {}
   private:
     virtual void Notify (void) { 
-      (EventMemberImplTraits<OBJ>::GetReference (m_obj).*m_function) (m_a1, m_a2, m_a3, m_a4);
+      (EventMemberImplObjTraits<OBJ>::GetReference (m_obj).*m_function) (m_a1, m_a2, m_a3, m_a4);
     }
     OBJ m_obj;
-    F m_function;
-    T1 m_a1;
-    T2 m_a2;
-    T3 m_a3;
-    T4 m_a4;
+    MEM m_function;
+    typename TypeTraits<T1>::ReferencedType m_a1;
+    typename TypeTraits<T2>::ReferencedType m_a2;
+    typename TypeTraits<T3>::ReferencedType m_a3;
+    typename TypeTraits<T4>::ReferencedType m_a4;
   } *ev = new EventMemberImpl4 (obj, mem_ptr, a1, a2, a3, a4);
-  return ev;
+  return Ptr<EventImpl> (ev, false);
 }
 
-template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4, typename T5>
-EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (T1,T2,T3,T4,T5), OBJ obj, 
-                                 T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) 
+template <typename MEM, typename OBJ, 
+          typename T1, typename T2, typename T3, typename T4, typename T5>
+Ptr<EventImpl> Simulator::MakeEvent (MEM mem_ptr, OBJ obj, 
+                                     T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) 
 {
   // five argument version
   class EventMemberImpl5 : public EventImpl {
   public:
-    typedef void (T::*F)(T1, T2, T3, T4, T5);
-      
-    EventMemberImpl5 (OBJ obj, F function, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) 
+    EventMemberImpl5 (OBJ obj, MEM function, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) 
       : m_obj (obj), 
         m_function (function),
         m_a1 (a1),
@@ -754,223 +786,235 @@
     virtual ~EventMemberImpl5 () {}
   private:
     virtual void Notify (void) { 
-      (EventMemberImplTraits<OBJ>::GetReference (m_obj).*m_function) (m_a1, m_a2, m_a3, m_a4, m_a5);
+      (EventMemberImplObjTraits<OBJ>::GetReference (m_obj).*m_function) (m_a1, m_a2, m_a3, m_a4, m_a5);
     }
     OBJ m_obj;
-    F m_function;
-    T1 m_a1;
-    T2 m_a2;
-    T3 m_a3;
-    T4 m_a4;
-    T5 m_a5;
+    MEM m_function;
+    typename TypeTraits<T1>::ReferencedType m_a1;
+    typename TypeTraits<T2>::ReferencedType m_a2;
+    typename TypeTraits<T3>::ReferencedType m_a3;
+    typename TypeTraits<T4>::ReferencedType m_a4;
+    typename TypeTraits<T5>::ReferencedType m_a5;
   } *ev = new EventMemberImpl5 (obj, mem_ptr, a1, a2, a3, a4, a5);
-  return ev;
+  return Ptr<EventImpl> (ev, false);
 }
 
-template <typename T1>
-EventImpl *Simulator::MakeEvent (void (*f) (T1), T1 a1) 
+template <typename U1, typename T1>
+Ptr<EventImpl> Simulator::MakeEvent (void (*f) (U1), T1 a1) 
 {
   // one arg version
   class EventFunctionImpl1 : public EventImpl {
   public:
-  	typedef void (*F)(T1);
+    typedef void (*F)(U1);
       
-  	EventFunctionImpl1 (F function, T1 a1) 
-  		: m_function (function),
-  		  m_a1 (a1)
-  	{ }
+    EventFunctionImpl1 (F function, T1 a1) 
+      : m_function (function),
+        m_a1 (a1)
+    { }
   protected:
-  	virtual ~EventFunctionImpl1 () {}
+    virtual ~EventFunctionImpl1 () {}
   private:
-  	virtual void Notify (void) { 
-  		(*m_function) (m_a1);
-  	}
-  	F m_function;
-  	T1 m_a1;
-  } *ev = new EventFunctionImpl1(f, a1);
-  return ev;
+    virtual void Notify (void) { 
+      (*m_function) (m_a1);
+    }
+    F m_function;
+    typename TypeTraits<T1>::ReferencedType m_a1;
+  } *ev = new EventFunctionImpl1 (f, a1);
+  return Ptr<EventImpl> (ev, false);
 }
 
-template <typename T1, typename T2>
-EventImpl *Simulator::MakeEvent (void (*f) (T1,T2), T1 a1, T2 a2) 
+template <typename U1, typename U2, typename T1, typename T2>
+Ptr<EventImpl> Simulator::MakeEvent (void (*f) (U1,U2), T1 a1, T2 a2) 
 {
   // two arg version
   class EventFunctionImpl2 : public EventImpl {
   public:
-  	typedef void (*F)(T1, T2);
+    typedef void (*F)(U1, U2);
       
-  	EventFunctionImpl2 (F function, T1 a1, T2 a2) 
-  		: m_function (function),
-  		  m_a1 (a1),
-  		  m_a2 (a2)
-  	{ }
+    EventFunctionImpl2 (F function, T1 a1, T2 a2) 
+      : m_function (function),
+        m_a1 (a1),
+        m_a2 (a2)
+    {}
   protected:
-  	virtual ~EventFunctionImpl2 () {}
+    virtual ~EventFunctionImpl2 () {}
   private:
-  	virtual void Notify (void) { 
-  		(*m_function) (m_a1, m_a2);
-  	}
-  	F m_function;
-  	T1 m_a1;
-  	T2 m_a2;
+    virtual void Notify (void) { 
+      (*m_function) (m_a1, m_a2);
+    }
+    F m_function;
+    typename TypeTraits<T1>::ReferencedType m_a1;
+    typename TypeTraits<T2>::ReferencedType m_a2;
   } *ev = new EventFunctionImpl2 (f, a1, a2);
-  return ev;
+  return Ptr<EventImpl> (ev, false);
 }
 
-template <typename T1, typename T2, typename T3>
-EventImpl *Simulator::MakeEvent (void (*f) (T1,T2,T3), T1 a1, T2 a2, T3 a3)
+template <typename U1, typename U2, typename U3,
+          typename T1, typename T2, typename T3>
+Ptr<EventImpl> Simulator::MakeEvent (void (*f) (U1,U2,U3), T1 a1, T2 a2, T3 a3)
 {
   // three arg version
   class EventFunctionImpl3 : public EventImpl {
   public:
-  	typedef void (*F)(T1, T2, T3);
+    typedef void (*F)(U1, U2, U3);
       
-  	EventFunctionImpl3 (F function, T1 a1, T2 a2, T3 a3) 
-  		: m_function (function),
-  		  m_a1 (a1),
-  		  m_a2 (a2),
-  		  m_a3 (a3)
-  	{ }
+    EventFunctionImpl3 (F function, T1 a1, T2 a2, T3 a3) 
+      : m_function (function),
+        m_a1 (a1),
+        m_a2 (a2),
+        m_a3 (a3)
+    { }
   protected:
-  	virtual ~EventFunctionImpl3 () {}
+    virtual ~EventFunctionImpl3 () {}
   private:
-  	virtual void Notify (void) { 
-  		(*m_function) (m_a1, m_a2, m_a3);
-  	}
-  	F m_function;
-  	T1 m_a1;
-  	T2 m_a2;
-  	T3 m_a3;
+    virtual void Notify (void) { 
+      (*m_function) (m_a1, m_a2, m_a3);
+    }
+    F m_function;
+    typename TypeTraits<T1>::ReferencedType m_a1;
+    typename TypeTraits<T2>::ReferencedType m_a2;
+    typename TypeTraits<T3>::ReferencedType m_a3;
   } *ev = new EventFunctionImpl3 (f, a1, a2, a3);
-  return ev;
+  return Ptr<EventImpl> (ev, false);
 }
 
-template <typename T1, typename T2, typename T3, typename T4>
-EventImpl *Simulator::MakeEvent (void (*f) (T1,T2,T3,T4), T1 a1, T2 a2, T3 a3, T4 a4) 
+template <typename U1, typename U2, typename U3, typename U4,
+          typename T1, typename T2, typename T3, typename T4>
+Ptr<EventImpl> Simulator::MakeEvent (void (*f) (U1,U2,U3,U4), T1 a1, T2 a2, T3 a3, T4 a4) 
 {
   // four arg version
   class EventFunctionImpl4 : public EventImpl {
   public:
-  	typedef void (*F)(T1, T2, T3, T4);
+    typedef void (*F)(U1, U2, U3, U4);
       
-  	EventFunctionImpl4 (F function, T1 a1, T2 a2, T3 a3, T4 a4) 
-  		: m_function (function),
-  		  m_a1 (a1),
-  		  m_a2 (a2),
-  		  m_a3 (a3),
-  		  m_a4 (a4)
-  	{ }
+    EventFunctionImpl4 (F function, T1 a1, T2 a2, T3 a3, T4 a4) 
+      : m_function (function),
+        m_a1 (a1),
+        m_a2 (a2),
+        m_a3 (a3),
+        m_a4 (a4)
+    { }
   protected:
-  	virtual ~EventFunctionImpl4 () {}
+    virtual ~EventFunctionImpl4 () {}
   private:
-  	virtual void Notify (void) { 
-  		(*m_function) (m_a1, m_a2, m_a3, m_a4);
-  	}
-  	F m_function;
-  	T1 m_a1;
-  	T2 m_a2;
-  	T3 m_a3;
-  	T4 m_a4;
+    virtual void Notify (void) { 
+      (*m_function) (m_a1, m_a2, m_a3, m_a4);
+    }
+    F m_function;
+    typename TypeTraits<T1>::ReferencedType m_a1;
+    typename TypeTraits<T2>::ReferencedType m_a2;
+    typename TypeTraits<T3>::ReferencedType m_a3;
+    typename TypeTraits<T4>::ReferencedType m_a4;
   } *ev = new EventFunctionImpl4 (f, a1, a2, a3, a4);
-  return ev;
+  return Ptr<EventImpl> (ev, false);
 }
 
-template <typename T1, typename T2, typename T3, typename T4, typename T5>
-EventImpl *Simulator::MakeEvent (void (*f) (T1,T2,T3,T4,T5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) 
+template <typename U1, typename U2, typename U3, typename U4, typename U5,
+          typename T1, typename T2, typename T3, typename T4, typename T5>
+Ptr<EventImpl> Simulator::MakeEvent (void (*f) (U1,U2,U3,U4,U5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) 
 {
   // five arg version
   class EventFunctionImpl5 : public EventImpl {
   public:
-  	typedef void (*F)(T1, T2, T3, T4, T5);
+    typedef void (*F)(U1,U2,U3,U4,U5);
       
-  	EventFunctionImpl5 (F function, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) 
-  		: m_function (function),
-  		  m_a1 (a1),
-  		  m_a2 (a2),
-  		  m_a3 (a3),
-  		  m_a4 (a4),
-  		  m_a5 (a5)
-  	{ }
+    EventFunctionImpl5 (F function, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) 
+      : m_function (function),
+        m_a1 (a1),
+        m_a2 (a2),
+        m_a3 (a3),
+        m_a4 (a4),
+        m_a5 (a5)
+    {}
   protected:
-  	virtual ~EventFunctionImpl5 () {}
+    virtual ~EventFunctionImpl5 () {}
   private:
-  	virtual void Notify (void) { 
-  		(*m_function) (m_a1, m_a2, m_a3, m_a4, m_a5);
-  	}
-  	F m_function;
-  	T1 m_a1;
-  	T2 m_a2;
-  	T3 m_a3;
-  	T4 m_a4;
-  	T5 m_a5;
+    virtual void Notify (void) { 
+      (*m_function) (m_a1, m_a2, m_a3, m_a4, m_a5);
+    }
+    F m_function;
+    typename TypeTraits<T1>::ReferencedType m_a1;
+    typename TypeTraits<T2>::ReferencedType m_a2;
+    typename TypeTraits<T3>::ReferencedType m_a3;
+    typename TypeTraits<T4>::ReferencedType m_a4;
+    typename TypeTraits<T5>::ReferencedType m_a5;
   } *ev = new EventFunctionImpl5 (f, a1, a2, a3, a4, a5);
-  return ev; 
+  return Ptr<EventImpl> (ev, false);
 }
 
-template <typename T, typename OBJ>
-EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (void), OBJ obj) 
+template <typename MEM, typename OBJ>
+EventId Simulator::Schedule (Time const &time, MEM mem_ptr, OBJ obj) 
 {
   return Schedule (time, MakeEvent (mem_ptr, obj));
 }
 
 
-template <typename T, typename OBJ, typename T1>
-EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (T1), OBJ obj, T1 a1) 
+template <typename MEM, typename OBJ,
+          typename T1>
+EventId Simulator::Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1) 
 {
   return Schedule (time, MakeEvent (mem_ptr, obj, a1));
 }
 
-template <typename T, typename OBJ, typename T1, typename T2>
-EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (T1,T2), OBJ obj, T1 a1, T2 a2) 
+template <typename MEM, typename OBJ, 
+          typename T1, typename T2>
+EventId Simulator::Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1, T2 a2)
 {
   return Schedule (time, MakeEvent (mem_ptr, obj, a1, a2));
 }
 
-template <typename T, typename OBJ, typename T1, typename T2, typename T3>
-EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (T1,T2,T3), OBJ obj, T1 a1, T2 a2, T3 a3) 
+template <typename MEM, typename OBJ,
+          typename T1, typename T2, typename T3>
+EventId Simulator::Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3) 
 {
   return Schedule (time, MakeEvent (mem_ptr, obj, a1, a2, a3));
 }
 
-template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4>
-EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (T1,T2,T3,T4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4) 
+template <typename MEM, typename OBJ, 
+          typename T1, typename T2, typename T3, typename T4>
+EventId Simulator::Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4) 
 {
   return Schedule (time, MakeEvent (mem_ptr, obj, a1, a2, a3, a4));
 }
 
-template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4, typename T5>
-EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (T1,T2,T3,T4,T5), OBJ obj, 
-  						 T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) 
+template <typename MEM, typename OBJ, 
+          typename T1, typename T2, typename T3, typename T4, typename T5>
+EventId Simulator::Schedule (Time const &time, MEM mem_ptr, OBJ obj, 
+                             T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) 
 {
   return Schedule (time, MakeEvent (mem_ptr, obj, a1, a2, a3, a4, a5));
 }
 
-template <typename T1>
-EventId Simulator::Schedule (Time const &time, void (*f) (T1), T1 a1) 
+template <typename U1, typename T1>
+EventId Simulator::Schedule (Time const &time, void (*f) (U1), T1 a1) 
 {
   return Schedule (time, MakeEvent (f, a1));
 }
 
-template <typename T1, typename T2>
-EventId Simulator::Schedule (Time const &time, void (*f) (T1,T2), T1 a1, T2 a2) 
+template <typename U1, typename U2, 
+          typename T1, typename T2>
+EventId Simulator::Schedule (Time const &time, void (*f) (U1,U2), T1 a1, T2 a2) 
 {
   return Schedule (time, MakeEvent (f, a1, a2));
 }
 
-template <typename T1, typename T2, typename T3>
-EventId Simulator::Schedule (Time const &time, void (*f) (T1,T2,T3), T1 a1, T2 a2, T3 a3)
+template <typename U1, typename U2, typename U3,
+          typename T1, typename T2, typename T3>
+EventId Simulator::Schedule (Time const &time, void (*f) (U1,U2,U3), T1 a1, T2 a2, T3 a3)
 {
   return Schedule (time, MakeEvent (f, a1, a2, a3));
 }
 
-template <typename T1, typename T2, typename T3, typename T4>
-EventId Simulator::Schedule (Time const &time, void (*f) (T1,T2,T3,T4), T1 a1, T2 a2, T3 a3, T4 a4) 
+template <typename U1, typename U2, typename U3, typename U4,
+          typename T1, typename T2, typename T3, typename T4>
+EventId Simulator::Schedule (Time const &time, void (*f) (U1,U2,U3,U4), T1 a1, T2 a2, T3 a3, T4 a4) 
 {
   return Schedule (time, MakeEvent (f, a1, a2, a3, a4));
 }
 
-template <typename T1, typename T2, typename T3, typename T4, typename T5>
-EventId Simulator::Schedule (Time const &time, void (*f) (T1,T2,T3,T4,T5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) 
+template <typename U1, typename U2, typename U3, typename U4, typename U5,
+          typename T1, typename T2, typename T3, typename T4, typename T5>
+EventId Simulator::Schedule (Time const &time, void (*f) (U1,U2,U3,U4,U5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) 
 {
   return Schedule (time, MakeEvent (f, a1, a2, a3, a4, a5));
 }
@@ -978,162 +1022,182 @@
 
 
 
-template <typename T, typename OBJ>
+template <typename MEM, typename OBJ>
 EventId
-Simulator::ScheduleNow (void (T::*mem_ptr) (void), OBJ obj) 
+Simulator::ScheduleNow (MEM mem_ptr, OBJ obj) 
 {
   return ScheduleNow (MakeEvent (mem_ptr, obj));
 }
 
 
-template <typename T, typename OBJ, typename T1>
+template <typename MEM, typename OBJ, 
+          typename T1>
 EventId
-Simulator::ScheduleNow (void (T::*mem_ptr) (T1), OBJ obj, T1 a1) 
+Simulator::ScheduleNow (MEM mem_ptr, OBJ obj, T1 a1) 
 {
   return ScheduleNow (MakeEvent (mem_ptr, obj, a1));
 }
 
-template <typename T, typename OBJ, typename T1, typename T2>
+template <typename MEM, typename OBJ, 
+          typename T1, typename T2>
 EventId
-Simulator::ScheduleNow (void (T::*mem_ptr) (T1,T2), OBJ obj, T1 a1, T2 a2) 
+Simulator::ScheduleNow (MEM mem_ptr, OBJ obj, T1 a1, T2 a2) 
 {
   return ScheduleNow (MakeEvent (mem_ptr, obj, a1, a2));
 }
 
-template <typename T, typename OBJ, typename T1, typename T2, typename T3>
+template <typename MEM, typename OBJ, 
+          typename T1, typename T2, typename T3>
 EventId
-Simulator::ScheduleNow (void (T::*mem_ptr) (T1,T2,T3), OBJ obj, T1 a1, T2 a2, T3 a3) 
+Simulator::ScheduleNow (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3) 
 {
   return ScheduleNow (MakeEvent (mem_ptr, obj, a1, a2, a3));
 }
 
-template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4>
+template <typename MEM, typename OBJ, 
+          typename T1, typename T2, typename T3, typename T4>
 EventId
-Simulator::ScheduleNow (void (T::*mem_ptr) (T1,T2,T3,T4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4) 
+Simulator::ScheduleNow (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4) 
 {
   return ScheduleNow (MakeEvent (mem_ptr, obj, a1, a2, a3, a4));
 }
 
-template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4, typename T5>
+template <typename MEM, typename OBJ, 
+          typename T1, typename T2, typename T3, typename T4, typename T5>
 EventId
-Simulator::ScheduleNow (void (T::*mem_ptr) (T1,T2,T3,T4,T5), OBJ obj, 
+Simulator::ScheduleNow (MEM mem_ptr, OBJ obj, 
                         T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) 
 {
   return ScheduleNow (MakeEvent (mem_ptr, obj, a1, a2, a3, a4, a5));
 }
 
-template <typename T1>
+template <typename U1,
+          typename T1>
 EventId
-Simulator::ScheduleNow (void (*f) (T1), T1 a1) 
+Simulator::ScheduleNow (void (*f) (U1), T1 a1) 
 {
   return ScheduleNow (MakeEvent (f, a1));
 }
 
-template <typename T1, typename T2>
+template <typename U1, typename U2,
+          typename T1, typename T2>
 EventId
-Simulator::ScheduleNow (void (*f) (T1,T2), T1 a1, T2 a2) 
+Simulator::ScheduleNow (void (*f) (U1,U2), T1 a1, T2 a2) 
 {
   return ScheduleNow (MakeEvent (f, a1, a2));
 }
 
-template <typename T1, typename T2, typename T3>
+template <typename U1, typename U2, typename U3,
+          typename T1, typename T2, typename T3>
 EventId
-Simulator::ScheduleNow (void (*f) (T1,T2,T3), T1 a1, T2 a2, T3 a3)
+Simulator::ScheduleNow (void (*f) (U1,U2,U3), T1 a1, T2 a2, T3 a3)
 {
   return ScheduleNow (MakeEvent (f, a1, a2, a3));
 }
 
-template <typename T1, typename T2, typename T3, typename T4>
+template <typename U1, typename U2, typename U3, typename U4,
+          typename T1, typename T2, typename T3, typename T4>
 EventId
-Simulator::ScheduleNow (void (*f) (T1,T2,T3,T4), T1 a1, T2 a2, T3 a3, T4 a4) 
+Simulator::ScheduleNow (void (*f) (U1,U2,U3,U4), T1 a1, T2 a2, T3 a3, T4 a4) 
 {
   return ScheduleNow (MakeEvent (f, a1, a2, a3, a4));
 }
 
-template <typename T1, typename T2, typename T3, typename T4, typename T5>
+template <typename U1, typename U2, typename U3, typename U4, typename U5,
+          typename T1, typename T2, typename T3, typename T4, typename T5>
 EventId
-Simulator::ScheduleNow (void (*f) (T1,T2,T3,T4,T5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) 
+Simulator::ScheduleNow (void (*f) (U1,U2,U3,U4,U5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) 
 {
   return ScheduleNow (MakeEvent (f, a1, a2, a3, a4, a5));
 }
 
 
 
-template <typename T, typename OBJ>
+template <typename MEM, typename OBJ>
 EventId
-Simulator::ScheduleDestroy (void (T::*mem_ptr) (void), OBJ obj) 
+Simulator::ScheduleDestroy (MEM mem_ptr, OBJ obj) 
 {
   return ScheduleDestroy (MakeEvent (mem_ptr, obj));
 }
 
 
-template <typename T, typename OBJ, typename T1>
+template <typename MEM, typename OBJ, 
+          typename T1>
 EventId
-Simulator::ScheduleDestroy (void (T::*mem_ptr) (T1), OBJ obj, T1 a1) 
+Simulator::ScheduleDestroy (MEM mem_ptr, OBJ obj, T1 a1) 
 {
   return ScheduleDestroy (MakeEvent (mem_ptr, obj, a1));
 }
 
-template <typename T, typename OBJ, typename T1, typename T2>
+template <typename MEM, typename OBJ, 
+          typename T1, typename T2>
 EventId
-Simulator::ScheduleDestroy (void (T::*mem_ptr) (T1,T2), OBJ obj, T1 a1, T2 a2) 
+Simulator::ScheduleDestroy (MEM mem_ptr, OBJ obj, T1 a1, T2 a2) 
 {
   return ScheduleDestroy (MakeEvent (mem_ptr, obj, a1, a2));
 }
 
-template <typename T, typename OBJ, typename T1, typename T2, typename T3>
+template <typename MEM, typename OBJ, 
+          typename T1, typename T2, typename T3>
 EventId
-Simulator::ScheduleDestroy (void (T::*mem_ptr) (T1,T2,T3), OBJ obj, T1 a1, T2 a2, T3 a3) 
+Simulator::ScheduleDestroy (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3) 
 {
   return ScheduleDestroy (MakeEvent (mem_ptr, obj, a1, a2, a3));
 }
 
-template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4>
+template <typename MEM, typename OBJ,
+          typename T1, typename T2, typename T3, typename T4>
 EventId
-Simulator::ScheduleDestroy (void (T::*mem_ptr) (T1,T2,T3,T4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4) 
+Simulator::ScheduleDestroy (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4) 
 {
   return ScheduleDestroy (MakeEvent (mem_ptr, obj, a1, a2, a3, a4));
 }
 
-template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4, typename T5>
+template <typename MEM, typename OBJ, 
+          typename T1, typename T2, typename T3, typename T4, typename T5>
 EventId
-Simulator::ScheduleDestroy (void (T::*mem_ptr) (T1,T2,T3,T4,T5), OBJ obj, 
+Simulator::ScheduleDestroy (MEM mem_ptr, OBJ obj, 
                             T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) 
 {
   return ScheduleDestroy (MakeEvent (mem_ptr, obj, a1, a2, a3, a4, a5));
 }
 
-template <typename T1>
+template <typename U1,
+          typename T1>
 EventId
-Simulator::ScheduleDestroy (void (*f) (T1), T1 a1) 
+Simulator::ScheduleDestroy (void (*f) (U1), T1 a1) 
 {
   return ScheduleDestroy (MakeEvent (f, a1));
 }
 
-template <typename T1, typename T2>
+template <typename U1, typename U2,
+          typename T1, typename T2>
 EventId
-Simulator::ScheduleDestroy (void (*f) (T1,T2), T1 a1, T2 a2) 
+Simulator::ScheduleDestroy (void (*f) (U1,U2), T1 a1, T2 a2) 
 {
   return ScheduleDestroy (MakeEvent (f, a1, a2));
 }
 
-template <typename T1, typename T2, typename T3>
+template <typename U1, typename U2, typename U3,
+          typename T1, typename T2, typename T3>
 EventId
-Simulator::ScheduleDestroy (void (*f) (T1,T2,T3), T1 a1, T2 a2, T3 a3)
+Simulator::ScheduleDestroy (void (*f) (U1,U2,U3), T1 a1, T2 a2, T3 a3)
 {
   return ScheduleDestroy (MakeEvent (f, a1, a2, a3));
 }
 
-template <typename T1, typename T2, typename T3, typename T4>
+template <typename U1, typename U2, typename U3, typename U4,
+          typename T1, typename T2, typename T3, typename T4>
 EventId
-Simulator::ScheduleDestroy (void (*f) (T1,T2,T3,T4), T1 a1, T2 a2, T3 a3, T4 a4) 
+Simulator::ScheduleDestroy (void (*f) (U1,U2,U3,U4), T1 a1, T2 a2, T3 a3, T4 a4) 
 {
   return ScheduleDestroy (MakeEvent (f, a1, a2, a3, a4));
 }
 
-template <typename T1, typename T2, typename T3, typename T4, typename T5>
+template <typename U1, typename U2, typename U3, typename U4, typename U5,
+          typename T1, typename T2, typename T3, typename T4, typename T5>
 EventId
-Simulator::ScheduleDestroy (void (*f) (T1,T2,T3,T4,T5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) 
+Simulator::ScheduleDestroy (void (*f) (U1,U2,U3,U4,U5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) 
 {
   return ScheduleDestroy (MakeEvent (f, a1, a2, a3, a4, a5));
 }
--- a/src/simulator/time.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/simulator/time.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -191,7 +191,28 @@
 std::ostream& 
 operator<< (std::ostream& os, Time const& time)
 {
-  os << time.GetTimeStep () << "ts";
+  std::string unit;
+  switch (TimeStepPrecision::Get ()) {
+  case TimeStepPrecision::S:
+    unit = "s";
+    break;
+  case TimeStepPrecision::MS:
+    unit = "ms";
+    break;
+  case TimeStepPrecision::US:
+    unit = "us";
+    break;
+  case TimeStepPrecision::NS:
+    unit = "ns";
+    break;
+  case TimeStepPrecision::PS:
+    unit = "ps";
+    break;
+  case TimeStepPrecision::FS:
+    unit = "fs";
+    break;
+  }
+  os << time.GetTimeStep () << unit;
   return os;
 }
 
@@ -393,12 +414,12 @@
 
   TimeStepPrecision::Set (TimeStepPrecision::NS);
 
-  Bind ("TimeStepPrecision", "S");
-  Bind ("TimeStepPrecision", "MS");
-  Bind ("TimeStepPrecision", "US");
-  Bind ("TimeStepPrecision", "NS");
-  Bind ("TimeStepPrecision", "PS");
-  Bind ("TimeStepPrecision", "FS");
+  DefaultValue::Bind ("TimeStepPrecision", "S");
+  DefaultValue::Bind ("TimeStepPrecision", "MS");
+  DefaultValue::Bind ("TimeStepPrecision", "US");
+  DefaultValue::Bind ("TimeStepPrecision", "NS");
+  DefaultValue::Bind ("TimeStepPrecision", "PS");
+  DefaultValue::Bind ("TimeStepPrecision", "FS");
 
   return ok;
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/simulator/waf	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,1 @@
+exec "`dirname "$0"`"/../../waf "$@"
\ No newline at end of file
--- a/src/simulator/wscript	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/simulator/wscript	Fri Sep 28 11:59:46 2007 +0100
@@ -15,8 +15,6 @@
 
 
 def configure(conf):
-    conf.env.append_value('NS3_MODULES', 'ns3-simulator')
-
     if Params.g_options.high_precision_as_double:
         conf.add_define('USE_HIGH_PRECISION_DOUBLE', 1)
         conf.env['USE_HIGH_PRECISION_DOUBLE'] = 1
@@ -49,11 +47,7 @@
 
 
 def build(bld):
-    sim = bld.create_obj('cpp', 'shlib')
-    sim.name = 'ns3-simulator'
-    sim.target = sim.name
-    sim.uselib_local = ['ns3-core']
-
+    sim = bld.create_ns3_module('simulator', ['core'])
     sim.source = [
         'high-precision.cc',
         'time.cc',
@@ -65,7 +59,9 @@
         'scheduler-map.cc',
         'event-impl.cc',
         'simulator.cc',
+        'time-default-value.cc',
         ]
+
     headers = bld.create_obj('ns3header')
     headers.source = [
         'high-precision.h',
@@ -76,6 +72,7 @@
         'scheduler.h',
         'scheduler-factory.h',
         'simulation-singleton.h',
+        'time-default-value.h',
         ]
 
     env = bld.env_of_name('default')
--- a/src/wscript	Thu Jul 19 13:17:35 2007 +0200
+++ b/src/wscript	Fri Sep 28 11:59:46 2007 +0100
@@ -2,6 +2,7 @@
 
 import os, os.path
 import shutil
+import types
 
 import Action
 import Common
@@ -9,35 +10,59 @@
 import Params
 
 
-all_modules = [
+all_modules = (
     'core',
     'common',
     'simulator',
     'node',
     'internet-node',
-    'devices/p2p',
-    'applications',
-    ]
-
+    'devices/point-to-point',
+    'devices/csma',
+    'applications/onoff',
+    'applications/packet-sink',
+    'applications/udp-echo',
+    'routing/global-routing',
+    'mobility',
+    )
 
 def set_options(opt):
     opt.sub_options('simulator')
-    
+
+    opt.add_option('--enable-rpath',
+                   help=("Link programs with rpath"
+                         " (normally not needed, see "
+                         " --run and --shell; moreover, only works in some"
+                         " specific platforms, such as Linux and Solaris)"),
+                   action="store_true", dest='enable_rpath', default=False)
+
+
 def configure(conf):
     conf.sub_config('core')
     conf.sub_config('simulator')
 
     blddir = os.path.abspath(os.path.join(conf.m_blddir, conf.env.variant()))
-    for module in all_modules:
-        conf.sub_config(module)
-        conf.env.append_value('NS3_MODULE_PATH', os.path.join(blddir, 'src', module))
+    conf.env['NS3_MODULE_PATH'] = [os.path.join(blddir)]
+    if Params.g_options.enable_rpath:
+        conf.env.append_value('RPATH', '-Wl,-rpath=%s' % (os.path.join(blddir),))
+
+    ## Used to link the 'run-tests' program with all of ns-3 code
+    conf.env['NS3_MODULES'] = ['ns3-' + module.split('/')[-1] for module in all_modules]
 
+def create_ns3_module(bld, name, dependencies=()):
+    module = bld.create_obj('cpp', 'objects')
+    module.name = 'ns3-' + name
+    module.target = module.name
+    module.add_objects = ['ns3-' + dep for dep in dependencies]
+    module.env.append_value('CXXFLAGS', module.env['shlib_CXXFLAGS'])
+    return module
+    
 
 def build(bld):
     Object.register('ns3header', Ns3Header)
-    Action.Action('ns3_headers', func=_ns3_headers_inst, color='BLUE')
+    Action.Action('ns3header', func=_ns3_headers_inst, color='BLUE')
+    bld.create_ns3_module = types.MethodType(create_ns3_module, bld)
     
-    bld.add_subdirs(all_modules)
+    bld.add_subdirs(list(all_modules))
 
 
 class Ns3Header(Object.genobj):
@@ -52,19 +77,15 @@
 
     def apply(self):
         ns3_dir_node = Params.g_build.m_srcnode.find_dir("ns3")
-        inputs = []
-        outputs = []
         for filename in self.to_list(self.source):
             src_node = self.path.find_source(filename)
             if src_node is None:
                 Params.fatal("source ns3 header file %s not found" % (filename,))
             dst_node = ns3_dir_node.find_build(os.path.basename(filename))
             assert dst_node is not None
-            inputs.append(src_node)
-            outputs.append(dst_node)
-        task = self.create_task('ns3_headers', self.env, 1)
-        task.set_inputs(inputs)
-        task.set_outputs(outputs)
+            task = self.create_task('ns3header', self.env, 1)
+            task.set_inputs([src_node])
+            task.set_outputs([dst_node])
 
     def install(self):
         for i in self.m_tasks:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tutorial/hello-simulator.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,29 @@
+/* -*- 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
+ */
+
+#include "ns3/log.h"
+
+NS_LOG_COMPONENT_DEFINE ("HelloSimulator");
+
+using namespace ns3;
+
+int 
+main (int argc, char *argv[])
+{
+  LogComponentEnable ("HelloSimulator", LOG_LEVEL_INFO);
+
+  NS_LOG_INFO ("Hello Simulator");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tutorial/tutorial-1.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,81 @@
+/* -*- 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
+ */
+
+#include "ns3/log.h"
+#include "ns3/ptr.h"
+#include "ns3/internet-node.h"
+#include "ns3/csma-channel.h"
+#include "ns3/mac48-address.h"
+#include "ns3/csma-net-device.h"
+#include "ns3/csma-topology.h"
+#include "ns3/csma-ipv4-topology.h"
+#include "ns3/udp-echo-client.h"
+#include "ns3/udp-echo-server.h"
+#include "ns3/simulator.h"
+#include "ns3/nstime.h"
+
+NS_LOG_COMPONENT_DEFINE ("UdpEchoSimulation");
+
+using namespace ns3;
+
+int 
+main (int argc, char *argv[])
+{
+  LogComponentEnable ("UdpEchoSimulation", LOG_LEVEL_INFO);
+
+  NS_LOG_INFO ("UDP Echo Simulation");
+
+  Ptr<Node> n0 = Create<InternetNode> ();
+  Ptr<Node> n1 = Create<InternetNode> ();
+  Ptr<Node> n2 = Create<InternetNode> ();
+  Ptr<Node> n3 = Create<InternetNode> ();
+
+  Ptr<CsmaChannel> lan = 
+    CsmaTopology::CreateCsmaChannel (DataRate (5000000), MilliSeconds (2));
+
+  uint32_t nd0 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n0, lan, 
+    "08:00:2e:00:00:00");
+
+  uint32_t nd1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n1, lan, 
+    "08:00:2e:00:00:01");
+
+  uint32_t nd2 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, lan, 
+    "08:00:2e:00:00:02");
+
+  uint32_t nd3 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n3, lan, 
+    "08:00:2e:00:00:03");
+
+  CsmaIpv4Topology::AddIpv4Address (n0, nd0, "10.1.1.1", "255.255.255.0");
+  CsmaIpv4Topology::AddIpv4Address (n1, nd1, "10.1.1.2", "255.255.255.0");
+  CsmaIpv4Topology::AddIpv4Address (n2, nd2, "10.1.1.3", "255.255.255.0");
+  CsmaIpv4Topology::AddIpv4Address (n3, nd3, "10.1.1.4", "255.255.255.0");
+
+  uint16_t port = 7;
+
+  Ptr<UdpEchoClient> client = Create<UdpEchoClient> (n0, "10.1.1.2", port, 
+    1, Seconds(1.), 1024);
+
+  Ptr<UdpEchoServer> server = Create<UdpEchoServer> (n1, port);
+
+  server->Start(Seconds(1.));
+  client->Start(Seconds(2.));
+
+  server->Stop (Seconds(10.));
+  client->Stop (Seconds(10.));
+
+  Simulator::Run ();
+  Simulator::Destroy ();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tutorial/tutorial-2.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,86 @@
+/* -*- 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
+ */
+
+#include "ns3/log.h"
+#include "ns3/ptr.h"
+#include "ns3/internet-node.h"
+#include "ns3/csma-channel.h"
+#include "ns3/mac48-address.h"
+#include "ns3/csma-net-device.h"
+#include "ns3/csma-topology.h"
+#include "ns3/csma-ipv4-topology.h"
+#include "ns3/udp-echo-client.h"
+#include "ns3/udp-echo-server.h"
+#include "ns3/simulator.h"
+#include "ns3/nstime.h"
+#include "ns3/ascii-trace.h"
+
+NS_LOG_COMPONENT_DEFINE ("UdpEchoSimulation");
+
+using namespace ns3;
+
+int 
+main (int argc, char *argv[])
+{
+  LogComponentEnable ("UdpEchoSimulation", LOG_LEVEL_INFO);
+
+  NS_LOG_INFO ("UDP Echo Simulation");
+
+  Ptr<Node> n0 = Create<InternetNode> ();
+  Ptr<Node> n1 = Create<InternetNode> ();
+  Ptr<Node> n2 = Create<InternetNode> ();
+  Ptr<Node> n3 = Create<InternetNode> ();
+
+  Ptr<CsmaChannel> lan = 
+    CsmaTopology::CreateCsmaChannel (DataRate (5000000), MilliSeconds (2));
+
+  uint32_t nd0 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n0, lan, 
+    "08:00:2e:00:00:00");
+
+  uint32_t nd1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n1, lan, 
+    "08:00:2e:00:00:01");
+
+  uint32_t nd2 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, lan, 
+    "08:00:2e:00:00:02");
+
+  uint32_t nd3 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n3, lan, 
+    "08:00:2e:00:00:03");
+
+  CsmaIpv4Topology::AddIpv4Address (n0, nd0, "10.1.1.1", "255.255.255.0");
+  CsmaIpv4Topology::AddIpv4Address (n1, nd1, "10.1.1.2", "255.255.255.0");
+  CsmaIpv4Topology::AddIpv4Address (n2, nd2, "10.1.1.3", "255.255.255.0");
+  CsmaIpv4Topology::AddIpv4Address (n3, nd3, "10.1.1.4", "255.255.255.0");
+
+  uint16_t port = 7;
+
+  Ptr<UdpEchoClient> client = Create<UdpEchoClient> (n0, "10.1.1.2", port, 
+    1, Seconds(1.), 1024);
+
+  Ptr<UdpEchoServer> server = Create<UdpEchoServer> (n1, port);
+
+  server->Start(Seconds(1.));
+  client->Start(Seconds(2.));
+
+  server->Stop (Seconds(10.));
+  client->Stop (Seconds(10.));
+
+  AsciiTrace asciitrace ("tutorial.tr");
+  asciitrace.TraceAllQueues ();
+  asciitrace.TraceAllNetDeviceRx ();
+
+  Simulator::Run ();
+  Simulator::Destroy ();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tutorial/tutorial-3.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,90 @@
+/* -*- 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
+ */
+
+#include "ns3/log.h"
+#include "ns3/ptr.h"
+#include "ns3/internet-node.h"
+#include "ns3/csma-channel.h"
+#include "ns3/mac48-address.h"
+#include "ns3/csma-net-device.h"
+#include "ns3/csma-topology.h"
+#include "ns3/csma-ipv4-topology.h"
+#include "ns3/udp-echo-client.h"
+#include "ns3/udp-echo-server.h"
+#include "ns3/simulator.h"
+#include "ns3/nstime.h"
+#include "ns3/ascii-trace.h"
+#include "ns3/pcap-trace.h"
+
+NS_LOG_COMPONENT_DEFINE ("UdpEchoSimulation");
+
+using namespace ns3;
+
+int 
+main (int argc, char *argv[])
+{
+  LogComponentEnable ("UdpEchoSimulation", LOG_LEVEL_INFO);
+
+  NS_LOG_INFO ("UDP Echo Simulation");
+
+  Ptr<Node> n0 = Create<InternetNode> ();
+  Ptr<Node> n1 = Create<InternetNode> ();
+  Ptr<Node> n2 = Create<InternetNode> ();
+  Ptr<Node> n3 = Create<InternetNode> ();
+
+  Ptr<CsmaChannel> lan = 
+    CsmaTopology::CreateCsmaChannel (DataRate (5000000), MilliSeconds (2));
+
+  uint32_t nd0 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n0, lan, 
+    "08:00:2e:00:00:00");
+
+  uint32_t nd1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n1, lan, 
+    "08:00:2e:00:00:01");
+
+  uint32_t nd2 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, lan, 
+    "08:00:2e:00:00:02");
+
+  uint32_t nd3 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n3, lan, 
+    "08:00:2e:00:00:03");
+
+  CsmaIpv4Topology::AddIpv4Address (n0, nd0, "10.1.1.1", "255.255.255.0");
+  CsmaIpv4Topology::AddIpv4Address (n1, nd1, "10.1.1.2", "255.255.255.0");
+  CsmaIpv4Topology::AddIpv4Address (n2, nd2, "10.1.1.3", "255.255.255.0");
+  CsmaIpv4Topology::AddIpv4Address (n3, nd3, "10.1.1.4", "255.255.255.0");
+
+  uint16_t port = 7;
+
+  Ptr<UdpEchoClient> client = Create<UdpEchoClient> (n0, "10.1.1.2", port, 
+    1, Seconds(1.), 1024);
+
+  Ptr<UdpEchoServer> server = Create<UdpEchoServer> (n1, port);
+
+  server->Start(Seconds(1.));
+  client->Start(Seconds(2.));
+
+  server->Stop (Seconds(10.));
+  client->Stop (Seconds(10.));
+
+  AsciiTrace asciitrace ("tutorial.tr");
+  asciitrace.TraceAllQueues ();
+  asciitrace.TraceAllNetDeviceRx ();
+
+  PcapTrace pcaptrace ("tutorial.pcap");
+  pcaptrace.TraceAllIp ();
+
+  Simulator::Run ();
+  Simulator::Destroy ();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tutorial/tutorial-4.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,137 @@
+/* -*- 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
+ */
+
+#include "ns3/log.h"
+#include "ns3/ptr.h"
+#include "ns3/internet-node.h"
+#include "ns3/point-to-point-channel.h"
+#include "ns3/csma-channel.h"
+#include "ns3/mac48-address.h"
+#include "ns3/point-to-point-net-device.h"
+#include "ns3/csma-net-device.h"
+#include "ns3/point-to-point-topology.h"
+#include "ns3/csma-topology.h"
+#include "ns3/csma-ipv4-topology.h"
+#include "ns3/udp-echo-client.h"
+#include "ns3/udp-echo-server.h"
+#include "ns3/simulator.h"
+#include "ns3/nstime.h"
+#include "ns3/ascii-trace.h"
+#include "ns3/pcap-trace.h"
+#include "ns3/global-route-manager.h"
+
+NS_LOG_COMPONENT_DEFINE ("UdpEchoSimulation");
+
+using namespace ns3;
+
+// Network topology
+//
+//                       point to point
+//                      +--------------+
+//                      |              |
+//       n0   n1   n2   n3             n4   n5   n6   n7
+//       |    |    |    |              |    |    |    |
+//       ================              ================
+//             lan0                          lan1
+//
+int 
+main (int argc, char *argv[])
+{
+  LogComponentEnable ("UdpEchoSimulation", LOG_LEVEL_INFO);
+
+  NS_LOG_INFO ("UDP Echo Simulation");
+
+  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> ();
+  Ptr<Node> n5 = Create<InternetNode> ();
+  Ptr<Node> n6 = Create<InternetNode> ();
+  Ptr<Node> n7 = Create<InternetNode> ();
+
+  Ptr<CsmaChannel> lan1 = 
+    CsmaTopology::CreateCsmaChannel (DataRate (5000000), MilliSeconds (2));
+
+  uint32_t nd0 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n0, lan1, 
+    "08:00:2e:00:00:00");
+
+  uint32_t nd1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n1, lan1, 
+    "08:00:2e:00:00:01");
+
+  uint32_t nd2 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, lan1, 
+    "08:00:2e:00:00:02");
+
+  uint32_t nd3 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n3, lan1, 
+    "08:00:2e:00:00:03");
+
+  CsmaIpv4Topology::AddIpv4Address (n0, nd0, "10.1.1.1", "255.255.255.0");
+  CsmaIpv4Topology::AddIpv4Address (n1, nd1, "10.1.1.2", "255.255.255.0");
+  CsmaIpv4Topology::AddIpv4Address (n2, nd2, "10.1.1.3", "255.255.255.0");
+  CsmaIpv4Topology::AddIpv4Address (n3, nd3, "10.1.1.4", "255.255.255.0");
+
+  Ptr<CsmaChannel> lan2 = 
+    CsmaTopology::CreateCsmaChannel (DataRate (5000000), MilliSeconds (2));
+
+  uint32_t nd4 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n4, lan2, 
+    "08:00:2e:00:00:04");
+
+  uint32_t nd5 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n5, lan2, 
+    "08:00:2e:00:00:05");
+
+  uint32_t nd6 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n6, lan2, 
+    "08:00:2e:00:00:06");
+
+  uint32_t nd7 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n7, lan2, 
+    "08:00:2e:00:00:07");
+
+  CsmaIpv4Topology::AddIpv4Address (n4, nd4, "10.1.2.1", "255.255.255.0");
+  CsmaIpv4Topology::AddIpv4Address (n5, nd5, "10.1.2.2", "255.255.255.0");
+  CsmaIpv4Topology::AddIpv4Address (n6, nd6, "10.1.2.3", "255.255.255.0");
+  CsmaIpv4Topology::AddIpv4Address (n7, nd7, "10.1.2.4", "255.255.255.0");
+
+  Ptr<PointToPointChannel> link = PointToPointTopology::AddPointToPointLink (
+    n3, n4, DataRate (500000), MilliSeconds (20));
+
+  PointToPointTopology::AddIpv4Addresses (link, n3, "10.1.3.1", 
+    n4, "10.1.3.2");
+
+  uint16_t port = 7;
+
+  Ptr<UdpEchoClient> client = Create<UdpEchoClient> (n0, "10.1.2.4", port, 
+    1, Seconds(1.), 1024);
+
+  Ptr<UdpEchoServer> server = Create<UdpEchoServer> (n7, port);
+
+  server->Start(Seconds(1.));
+  client->Start(Seconds(2.));
+
+  server->Stop (Seconds(10.));
+  client->Stop (Seconds(10.));
+
+  AsciiTrace asciitrace ("tutorial-4.tr");
+  asciitrace.TraceAllQueues ();
+  asciitrace.TraceAllNetDeviceRx ();
+
+  PcapTrace pcaptrace ("tutorial-4.pcap");
+  pcaptrace.TraceAllIp ();
+
+  GlobalRouteManager::PopulateRoutingTables ();
+
+  Simulator::Run ();
+  Simulator::Destroy ();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tutorial/waf	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,1 @@
+exec "`dirname "$0"`"/../waf "$@"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tutorial/wscript	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,22 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def build(bld):
+    obj = bld.create_ns3_program('hello-simulator',
+        ['core'])
+    obj.source = 'hello-simulator.cc'
+
+    obj = bld.create_ns3_program('tutorial-1',
+        ['core'])
+    obj.source = 'tutorial-1.cc'
+
+    obj = bld.create_ns3_program('tutorial-2',
+        ['core'])
+    obj.source = 'tutorial-2.cc'
+
+    obj = bld.create_ns3_program('tutorial-3',
+        ['core'])
+    obj.source = 'tutorial-3.cc'
+
+    obj = bld.create_ns3_program('tutorial-4',
+        ['core'])
+    obj.source = 'tutorial-4.cc'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tutorial/wscript-0	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,6 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def build(bld):
+    obj = bld.create_ns3_program('hello-simulator',
+        ['core'])
+    obj.source = 'hello-simulator.cc'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tutorial/wscript-1	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,10 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def build(bld):
+    obj = bld.create_ns3_program('hello-simulator',
+        ['core'])
+    obj.source = 'hello-simulator.cc'
+
+    obj = bld.create_ns3_program('tutorial-1',
+        ['core'])
+    obj.source = 'tutorial-1.cc'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tutorial/wscript-2	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,14 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def build(bld):
+    obj = bld.create_ns3_program('hello-simulator',
+        ['core'])
+    obj.source = 'hello-simulator.cc'
+
+    obj = bld.create_ns3_program('tutorial-1',
+        ['core'])
+    obj.source = 'tutorial-1.cc'
+
+    obj = bld.create_ns3_program('tutorial-2',
+        ['core'])
+    obj.source = 'tutorial-2.cc'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tutorial/wscript-3	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,18 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def build(bld):
+    obj = bld.create_ns3_program('hello-simulator',
+        ['core'])
+    obj.source = 'hello-simulator.cc'
+
+    obj = bld.create_ns3_program('tutorial-1',
+        ['core'])
+    obj.source = 'tutorial-1.cc'
+
+    obj = bld.create_ns3_program('tutorial-2',
+        ['core'])
+    obj.source = 'tutorial-2.cc'
+
+    obj = bld.create_ns3_program('tutorial-3',
+        ['core'])
+    obj.source = 'tutorial-3.cc'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tutorial/wscript-4	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,22 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def build(bld):
+    obj = bld.create_ns3_program('hello-simulator',
+        ['core'])
+    obj.source = 'hello-simulator.cc'
+
+    obj = bld.create_ns3_program('tutorial-1',
+        ['core'])
+    obj.source = 'tutorial-1.cc'
+
+    obj = bld.create_ns3_program('tutorial-2',
+        ['core'])
+    obj.source = 'tutorial-2.cc'
+
+    obj = bld.create_ns3_program('tutorial-3',
+        ['core'])
+    obj.source = 'tutorial-3.cc'
+
+    obj = bld.create_ns3_program('tutorial-4',
+        ['core'])
+    obj.source = 'tutorial-4.cc'
--- a/utils/bench-packets.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/utils/bench-packets.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -18,97 +18,181 @@
  *
  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
  */
-#include "ns3/wall-clock-ms.h"
+#include "ns3/system-wall-clock-ms.h"
 #include "ns3/packet.h"
-#include "ns3/chunk-constant-data.h"
-#include "ns3/chunk-udp.h"
-#include "ns3/chunk-ipv4.h"
+#include "ns3/packet-metadata.h"
 #include <iostream>
+#include <sstream>
 
 using namespace ns3;
 
+template <int N>
+class BenchHeader : public Header
+{
+public:
+  BenchHeader ();
+  bool IsOk (void) const;
+
+  static uint32_t GetUid (void);
+
+  static std::string GetName (void);
+  void Print (std::ostream &os) const;
+  uint32_t GetSerializedSize (void) const;
+  void Serialize (Buffer::Iterator start) const;
+  uint32_t Deserialize (Buffer::Iterator start);
+private:
+  bool m_ok;
+};
+
+template <int N>
+BenchHeader<N>::BenchHeader ()
+  : m_ok (false)
+{}
+
+template <int N>
+bool 
+BenchHeader<N>::IsOk (void) const
+{
+  return m_ok;
+}
+
+template <int N>
+uint32_t 
+BenchHeader<N>::GetUid (void)
+{
+  static uint32_t uid = AllocateUid<BenchHeader<N> > (GetName ());
+  return uid;
+}
+
+template <int N>
+std::string 
+BenchHeader<N>::GetName (void)
+{
+  std::ostringstream oss;
+  oss << "BenchHeader" << N;
+  return oss.str ();
+}
+
+template <int N>
+void 
+BenchHeader<N>::Print (std::ostream &os) const
+{
+  NS_ASSERT (false);
+}
+template <int N>
+uint32_t 
+BenchHeader<N>::GetSerializedSize (void) const
+{
+  return N;
+}
+template <int N>
+void 
+BenchHeader<N>::Serialize (Buffer::Iterator start) const
+{
+  start.WriteU8 (N, N);
+}
+template <int N>
+uint32_t
+BenchHeader<N>::Deserialize (Buffer::Iterator start)
+{
+  m_ok = true;
+  for (int i = 0; i < N; i++)
+    {
+      if (start.ReadU8 () != N)
+        {
+          m_ok = false;
+        }
+    }
+  return N;
+}
+
+
+
 static void 
 benchPtrA (uint32_t n)
 {
-  ChunkConstantData data = ChunkConstantData (2000, 1);
-  ChunkUdp udp;
-  ChunkIpv4 ipv4;
+  BenchHeader<25> ipv4;
+  BenchHeader<8> udp;
 
   for (uint32_t i = 0; i < n; i++) {
-      Packet p;
-      p.add (&data);
-      p.add (&udp);
-      p.add (&ipv4);
+      Packet p (2000);
+      p.AddHeader (udp);
+      p.AddHeader (ipv4);
       Packet o = p;
-      o.peek (&ipv4);
-      o.remove (&ipv4);
-      o.peek (&udp);
-      o.remove (&udp);
-      o.peek (&data);
-      o.remove (&data);
+      o.RemoveHeader (ipv4);
+      o.RemoveHeader (udp);
   }
 }
 
 static void 
 benchPtrB (uint32_t n)
 {
-  ChunkConstantData data = ChunkConstantData (2000, 1);
-  ChunkUdp udp;
-  ChunkIpv4 ipv4;
+  BenchHeader<25> ipv4;
+  BenchHeader<8> udp;
 
   for (uint32_t i = 0; i < n; i++) {
-      Packet p;
-      p.add (&data);
-      p.add (&udp);
-      p.add (&ipv4);
+      Packet p (2000);
+      p.AddHeader (udp);
+      p.AddHeader (ipv4);
   }
 }
 
 static void
 ptrC2 (Packet p)
 {
-  ChunkConstantData data = ChunkConstantData (2000, 1);
-  ChunkUdp udp;
+  BenchHeader<8> udp;
 
-  p.peek (&udp);
-  p.remove (&udp);
-  p.peek (&data);
-  p.remove (&data);
+  p.RemoveHeader (udp);
 }
 
 static void 
 ptrC1 (Packet p)
 {
-  ChunkIpv4 ipv4;
-  p.peek (&ipv4);
-  p.remove (&ipv4);
+  BenchHeader<25> ipv4;
+  p.RemoveHeader (ipv4);
   ptrC2 (p);
 }
 
 static void
 benchPtrC (uint32_t n)
 {
-  ChunkConstantData data = ChunkConstantData (2000, 1);
-  ChunkUdp udp;
-  ChunkIpv4 ipv4;
+  BenchHeader<25> ipv4;
+  BenchHeader<8> udp;
 
   for (uint32_t i = 0; i < n; i++) {
-      Packet p;
-      p.add (&data);
-      p.add (&udp);
-      p.add (&ipv4);
+      Packet p (2000);
+      p.AddHeader (udp);
+      p.AddHeader (ipv4);
       ptrC1 (p);
   }
 }
 
+#if 0
+static void
+benchPrint (uint32_t n)
+{
+  PacketPrinter printer;
+  BenchHeader<25> ipv4;
+  BenchHeader<8> udp;
+  Packet p (2000);
+  p.AddHeader (udp);
+  p.AddHeader (ipv4);
+
+  for (uint32_t i = 0; i < n; i++) 
+    {
+      p.Print (std::cerr, printer);
+    }  
+}
+#endif
+
 
 static void
 runBench (void (*bench) (uint32_t), uint32_t n, char const *name)
 {
-  WallClockMs time;
-  time.start ();
+  SystemWallClockMs time;
+  time.Start ();
   (*bench) (n);
-  unsigned long long deltaMs = time.end ();
+  unsigned long long deltaMs = time.End ();
   double ps = n;
   ps *= 1000;
   ps /= deltaMs;
@@ -119,17 +203,31 @@
 {
   uint32_t n = 0;
   while (argc > 0) {
-      if (strncmp ("--n=", argv[0],strlen ("--n=")) == 0) {
+      if (strncmp ("--n=", argv[0],strlen ("--n=")) == 0) 
+        {
           char const *nAscii = argv[0] + strlen ("--n=");
           n = atoi (nAscii);
-      }
+        }
       argc--;
       argv++;
   }
 
+
   runBench (&benchPtrA, n, "a");
   runBench (&benchPtrB, n, "b");
   runBench (&benchPtrC, n, "c");
 
+  Packet::EnableMetadata ();
+  //runBench (&benchPrint, n, "print");
+  PacketMetadata::SetOptOne (false);
+  runBench (&benchPtrA, n, "meta-a");
+  runBench (&benchPtrB, n, "meta-b");
+  runBench (&benchPtrC, n, "meta-c");
+  PacketMetadata::SetOptOne (true);
+  runBench (&benchPtrA, n, "meta-a-opt");
+  runBench (&benchPtrB, n, "meta-b-opt");
+  runBench (&benchPtrC, n, "meta-c-opt");
+
+
   return 0;
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/utils/print-trace-sources.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,100 @@
+#include "ns3/internet-node.h"
+#include "ns3/ptr.h"
+#include "ns3/trace-resolver.h"
+#include "ns3/node-list.h"
+#include "ns3/point-to-point-net-device.h"
+#include "ns3/csma-net-device.h"
+#include "ns3/queue.h"
+#include "ns3/mobility-model-notifier.h"
+
+using namespace ns3;
+
+void
+PrintSimpleText (const TraceResolver::SourceCollection *sources, std::ostream &os)
+{
+  for (TraceResolver::SourceCollection::Iterator i = sources->Begin (); i != sources->End (); i++)
+    {
+      os << "source=" << i->path << std::endl;
+      os << "TraceContext=[";
+      i->context.PrintAvailable (os, ",");
+      os << "]" << std::endl;
+      os << "help=\"" << i->doc.GetHelp () << "\"" << std::endl;
+      os << "void TraceSinkCallback (const TraceContext &";
+      for (TraceDoc::Iterator k = i->doc.ArgsBegin (); k != i->doc.ArgsEnd (); k++)
+        {
+          os << ", " << k->first;
+        }
+      os << ")" << std::endl;
+      os << "argument 1  --  the trace context associated to the connected trace source." << std::endl;
+      uint32_t k = 2;
+      for (TraceDoc::Iterator j = i->doc.ArgsBegin (); j != i->doc.ArgsEnd (); j++)
+        {
+          os << "argument " << k << "  --  " << j->second << "." << std::endl;
+          k++;
+        }
+      os << std::endl;
+    }
+}
+void
+PrintDoxygenText (const TraceResolver::SourceCollection *sources, std::ostream &os)
+{
+  uint32_t z = 0;
+  for (TraceResolver::SourceCollection::Iterator i = sources->Begin (); i != sources->End (); i++)
+    {
+      os << "///" << std::endl;
+      os << "/// \\ingroup TraceSourceList" << std::endl; 
+      os << "/// \\brief " << i->doc.GetHelp () << std::endl;
+      os << "/// \\param arg1 the trace context associated to the connected trace source." << std::endl;
+      uint32_t j = 2;
+      for (TraceDoc::Iterator l = i->doc.ArgsBegin (); l != i->doc.ArgsEnd (); l++)
+        {
+          os << "/// \\param arg" << j << " " << l->second << "." << std::endl;
+          j++;
+        }
+      os << "///" << std::endl;
+      os << "///" << std::endl;
+      os << "/// The path to this trace source is: " << i->path << "." << std::endl;
+      os << "///" << std::endl;
+      if (i->context.Begin ().IsLast ())
+        {
+          os << "/// No data can be extracted from \\p arg1 with ns3::TraceContext::GetElement." << std::endl;
+        }
+      else
+        {
+          os << "/// The following classes can be extracted from \\p arg1 with " << std::endl;
+          os << "/// ns3::TraceContext::GetElement:" << std::endl;
+          for (TraceContext::Iterator m = i->context.Begin (); !m.IsLast (); m.Next ())
+            {
+              os << "///  - " << m.Get () << std::endl;
+            }
+        }
+      os << "void TraceSinkCallback" << z << " (const TraceContext & arg1" ;
+      j = 2;
+      for (TraceDoc::Iterator k = i->doc.ArgsBegin (); k != i->doc.ArgsEnd (); k++)
+        {
+          os << ", " << k->first << " arg" << j;
+          j++;
+        }
+      os << ");" << std::endl;
+      os << std::endl;
+      z++;
+    }
+}
+
+
+int main (int argc, char *argv[])
+{
+  Ptr<Node> node = Create<InternetNode> ();
+  node->AddInterface (Create<MobilityModelNotifier> ());
+
+  Ptr<PointToPointNetDevice> p2p = Create<PointToPointNetDevice> (node);
+  p2p->AddQueue (Queue::CreateDefault ());
+  Ptr<CsmaNetDevice> csma = Create<CsmaNetDevice> (node);
+  csma->AddQueue (Queue::CreateDefault ());
+
+  TraceResolver::SourceCollection collection;
+  NodeList::GetTraceResolver ()->CollectSources ("", TraceContext (), &collection);
+  PrintDoxygenText (&collection, std::cout);
+
+  return 0;
+}
--- a/utils/run-tests.cc	Thu Jul 19 13:17:35 2007 +0200
+++ b/utils/run-tests.cc	Fri Sep 28 11:59:46 2007 +0100
@@ -20,10 +20,13 @@
  */
 
 #include "ns3/test.h"
+#include "ns3/packet-metadata.h"
+
 
 int main (int argc, char *argv[])
 {
 #ifdef RUN_SELF_TESTS
+  ns3::PacketMetadata::Enable ();
   ns3::TestManager::EnableVerbose ();
   bool success = ns3::TestManager::RunTests ();
   if (!success)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/utils/waf	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,1 @@
+exec "`dirname "$0"`"/../waf "$@"
--- a/utils/wscript	Thu Jul 19 13:17:35 2007 +0200
+++ b/utils/wscript	Fri Sep 28 11:59:46 2007 +0100
@@ -4,20 +4,22 @@
 def build(bld):
     env = bld.env_of_name('default')
 
-    def create_ns_prog(name, source):
-        obj = bld.create_obj('cpp', 'program')
-        obj.target = name
-        obj.source = source
-        return obj
-
-    unit_tests = create_ns_prog('run-tests', 'run-tests.cc')
+    unit_tests = bld.create_ns3_program('run-tests')
     unit_tests.install_var  = 0 # do not install
     unit_tests.unit_test    = 1 # runs on 'waf check'
+    unit_tests.source = 'run-tests.cc'
     ## link unit test program with all ns3 modules
-    unit_tests.uselib_local = env['NS3_MODULES']
+    unit_tests.uselib_local = 'ns3'
     
-    obj = create_ns_prog('bench-simulator', 'bench-simulator.cc')
-    obj.uselib_local = "ns3-core ns3-common ns3-simulator"
+    obj = bld.create_ns3_program('bench-simulator', ['simulator'])
+    obj.source = 'bench-simulator.cc'
+
+    obj = bld.create_ns3_program('bench-packets', ['common'])
+    obj.source = 'bench-packets.cc'
 
-    obj = create_ns_prog('replay-simulation', 'replay-simulation.cc')
-    obj.uselib_local = "ns3-core ns3-common ns3-simulator"
+    obj = bld.create_ns3_program('replay-simulation', ['simulator'])
+    obj.source = 'replay-simulation.cc'
+
+    obj = bld.create_ns3_program('print-trace-sources',
+                                 ['internet-node', 'csma-cd', 'point-to-point'])
+    obj.source = 'print-trace-sources.cc'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/waf	Fri Sep 28 11:59:46 2007 +0100
@@ -0,0 +1,369 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2005, 2006, 2007 (ita)
+
+"""
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+3. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+"""
+
+import os, sys
+if 'PSYCOWAF' in os.environ:
+	try:
+		import psyco
+		psyco.full()
+	except:
+		pass
+
+VERSION="1.2.0"
+REVISION="1894439586"
+INSTALL=sys.platform=='win32' and 'c:/temp' or '/usr/local'
+cwd = os.getcwd()
+
+def decodeAscii85(s):
+	out=[]
+	app=out.append
+	s=''.join(s.split()).replace('z','!!!!!')
+	p1,p2=divmod(len(s), 5)
+	stop=5*p1
+	p3,p4=s[0:stop],s[stop:]
+	for i in range(p1):
+		off=i*5
+		a=ord(p3[off])-33
+		b=ord(p3[off+1])-33
+		c=ord(p3[off+2])-33
+		d=ord(p3[off+3])-33
+		e=ord(p3[off+4])-33
+		num=(52200625L*a)+(614125*b)+(7225*c)+(85*d)+e
+		x,p=divmod(num,256)
+		x,o=divmod(x,256)
+		m,n=divmod(x,256)
+		app(chr(m)+chr(n)+chr(o)+chr(p))
+	if p2:
+		while len(p4)<5: p4=p4+'!'
+		a=ord(p4[0])-33
+		b=ord(p4[1])-33
+		c=ord(p4[2])-33
+		d=ord(p4[3])-33
+		e=ord(p4[4])-33
+		num=(52200625L*a)+(614125*b)+(7225*c)+(85*d)+e
+		x,p=divmod(num,256)
+		x,o=divmod(x,256)
+		m,n=divmod(x, 256)
+		if p2==2: app(chr(m))
+		elif p2==3: app(chr(m)+chr(n))
+		elif p2==4: app(chr(m)+chr(n)+chr(o))
+	return ''.join(out)
+
+# wafdir is needed to parse the command-line arguments or print the version number
+wafdir=None # SPECIAL LINE
+
+def uncompress_wafdir(newdir):
+	file = open(sys.argv[0], 'rb')
+	while 1:
+		line = file.readline()
+		if not line:
+			print "This is a stripped-down waf, there is no wafadmin directory available"
+			print "Please set WAFDIR to a directory containing a directory named wafadmin"
+			print "Or use the full waf version available freely at http://freehackers.org/~tnagy/bksys.html"
+			print "\033[91mNo wafadmin: cannot execute anything (error)\033[0m"
+			sys.exit(1)
+		line=line.rstrip()
+		if line=='# ===>BEGIN WOOF<===':
+			cnt = file.readline()
+			if not cnt:
+				print "Corrupted waf (1)"
+				sys.exit(1)
+
+			line = file.readline().rstrip()
+			if line!='# ===>END WOOF<===':
+				print "Corrupted waf (2)"
+				sys.exit(1)
+			break
+	if not cnt:
+		print "Corrupted waf (3)"
+		sys.exit(1)
+
+	cnt = decodeAscii85(cnt[1:])
+
+	# create wafadmin
+	import shutil
+	try: shutil.rmtree(newdir)
+	except OSError: pass
+	try: os.makedirs(newdir)
+	except OSError:
+		print "Could uncompress waf-local into %s"%newdir
+		print "Please install waf system-wide or move waf in a writeable directory"
+		sys.exit(1)
+
+	os.chdir(newdir)
+	file = open('wafadmin.tar.bz2', 'wb')
+	file.write(cnt)
+	file.close()
+
+	# now we have the tar file to open
+	import tarfile
+	tar = tarfile.open('wafadmin.tar.bz2')
+	for tarinfo in tar:
+		tar.extract(tarinfo)
+	tar.close()
+
+	# cleanup the tarfile and chdir to the previous directory
+	os.chmod('wafadmin', 0755)
+	os.chmod('wafadmin'+os.sep+'Tools', 0755)
+	os.unlink('wafadmin.tar.bz2')
+	os.chdir(cwd)
+
+	global wafdir
+	wafdir = newdir
+
+def try_wafdir(dir):
+	global wafdir
+	if wafdir: return
+	try:
+		os.stat(os.path.join(dir, 'wafadmin'))
+		wafdir = os.path.abspath(dir)
+	except OSError:
+		pass
+
+def find_wafadmin():
+	global wafdir
+	name = sys.argv[0]
+
+	# wafadmin may be in $WAFDIR (developers)
+	if 'WAFDIR' in os.environ:
+		try_wafdir(os.environ['WAFDIR'])
+		if wafdir: return
+
+	# waf-light is a special beast
+	if name[-5:] == 'light':
+		try_wafdir(os.path.dirname(os.path.abspath(name)))
+		if wafdir: return
+		print "\033[91mwaf-light in use, wafadmin not found -> export WAFDIR=/folder\033[0m"
+		sys.exit(1)
+
+	if not wafdir:
+		dir = "/lib/waf-%s-%s/" % (VERSION, REVISION)
+		for i in [INSTALL, '/usr', '/usr/local', '/opt']:
+			try_wafdir(i+dir)
+			if wafdir: return
+
+	# remove $HOME/.waf-version if asked to
+	if wafdir:
+		if "--nocache" in sys.argv:
+			import shutil
+			print "removing the local wafdir", wafdir
+			try: shutil.rmtree(wafdir)
+			except OSError: pass
+		try: os.stat(wafdir)
+		except OSError: wafdir=None
+
+	if wafdir: return
+
+	# look in the directory containing waf
+	if sys.platform == 'win32': s='waf-%s-%s'
+	else: s='.waf-%s-%s'
+	dir = os.path.join(os.path.dirname(os.path.abspath(name)), s % (VERSION, REVISION))
+	try_wafdir(dir)
+	if wafdir: return
+
+	# not found, uncompress
+	wafdir = dir
+	uncompress_wafdir(dir)
+
+# run the test
+find_wafadmin()
+if "-vv" in sys.argv: print "wafdir is ", wafdir
+
+# Update sys.path and import our modules
+wafadmindir = os.path.join(wafdir, 'wafadmin')
+tooldir = os.path.join(wafadmindir, 'Tools')
+sys.path = [wafadmindir, tooldir] + sys.path
+
+import Options, Params, Utils
+from Params import fatal, warning
+
+# Set the directory containing the tools
+Params.g_tooldir = [tooldir]
+Params.g_cwd_launch = cwd
+
+if Params.g_version != VERSION:
+	fatal('version mismatch waf %s <-> wafadmin %s (wafdir %s)' % (VERSION, Params.g_version, wafdir))
+
+# some command-line options can be processed immediately
+if '--version' in sys.argv:
+	opt_obj = Options.Handler()
+	opt_obj.parse_args()
+	sys.exit(0)
+
+# now find the wscript file
+msg1 = 'Waf: *** Nothing to do! Please run waf from a directory containing a file named "wscript"'
+
+# Some people want to configure their projects gcc-style:
+# mkdir build && cd build && ../waf configure && ../waf
+# check that this is really what is wanted
+build_dir_override = None
+candidate = None
+
+lst = os.listdir(cwd)
+xml = 0
+#check if a wscript or a wscript_xml file is in current directory
+if (not 'wscript' in lst) and (not 'wscript_xml' in lst):
+	if 'configure' in sys.argv:
+		#set the build directory with the current directory
+		build_dir_override = cwd
+	if 'wscript_build' in lst:
+		#try to find the wscript root
+		candidate = cwd
+else:
+	#wscript or wscript_xml is in current directory, use this directory as candidate
+	candidate = cwd
+
+try:
+	#check the following dirs for wscript or wscript_xml
+	search_for_candidate = True
+	if not candidate:
+		#check first the calldir if there is wscript or wscript_xml
+		#for example: /usr/src/configure the calldir would be /usr/src
+		calldir = os.path.abspath(os.path.dirname(sys.argv[0]))
+		lst_calldir = os.listdir(calldir)
+		if 'wscript'       in lst_calldir:
+			candidate = calldir
+			search_for_candidate = False
+		if 'wscript_xml'   in lst_calldir:
+			candidate = calldir
+			xml = 1
+			search_for_candidate = False
+	if "--make-waf" in sys.argv and candidate:
+		search_for_candidate = False
+
+	#check all directories above current dir for wscript or wscript_xml if still not found
+	while search_for_candidate:
+		if len(cwd) <= 3:
+			break # stop at / or c:
+		dirlst = os.listdir(cwd)
+		if 'wscript' in dirlst:
+			candidate = cwd
+			xml = 0
+		if 'wscript_xml' in dirlst:
+			candidate = cwd
+			xml = 1
+			break
+		if 'configure' in sys.argv and candidate:
+			break
+		if Params.g_lockfile in dirlst:
+			break
+		cwd = cwd[:cwd.rfind(os.sep)] # climb up
+except:
+	fatal(msg1)
+
+if not candidate:
+	# check if the user only wanted to display the help
+	if '-h' in sys.argv or '--help' in sys.argv:
+		warning('No wscript file found: the help message may be incomplete')
+		opt_obj = Options.Handler()
+		opt_obj.parse_args()
+		sys.exit(0)
+	else:
+		fatal(msg1)
+
+# We have found wscript, but there is no guarantee that it is valid
+os.chdir(candidate)
+
+# xml -> jump to the parser
+if xml:
+	from XMLScripting import compile
+	compile(candidate+os.sep+'wscript_xml')
+else:
+	# define the main module containing the functions init, shutdown, ..
+	Utils.set_main_module(os.path.join(candidate, 'wscript'))
+
+if build_dir_override:
+	d = getattr(Utils.g_module, 'blddir', None)
+	if d:
+		# test if user has set the blddir in wscript.
+		msg = 'Overriding build directory %s with %s' % (d, build_dir_override)
+		Params.niceprint(msg, 'WARNING', 'waf')
+	Utils.g_module.blddir = build_dir_override
+
+# fetch the custom command-line options recursively and in a procedural way
+opt_obj = Options.Handler()
+opt_obj.sub_options('') # will look in wscript
+opt_obj.parse_args()
+
+# use the parser results
+if Params.g_commands['dist']:
+	# try to use the user-defined dist function first, fallback to the waf scheme
+	fun = getattr(Utils.g_module, 'dist', None)
+	if fun: fun(); sys.exit(0)
+
+	appname = getattr(Utils.g_module, 'APPNAME', 'noname')
+
+	get_version = getattr(Utils.g_module, 'get_version', None)
+	if get_version: version = get_version()
+	else: version = getattr(Utils.g_module, 'VERSION', None)
+	if not version: version = '1.0'
+
+	from Scripting import Dist
+	Dist(appname, version)
+	sys.exit(0)
+elif Params.g_commands['distclean']:
+	# try to use the user-defined distclean first, fallback to the waf scheme
+	fun = getattr(Utils.g_module, 'distclean', None)
+	if fun: fun(); sys.exit(0)
+	from Scripting import DistClean
+	DistClean()
+	sys.exit(0)
+elif Params.g_commands['distcheck']:
+	# try to use the user-defined dist function first, fallback to the waf scheme
+	fun = getattr(Utils.g_module, 'dist', None)
+	if fun: fun(); sys.exit(0)
+
+	appname = getattr(Utils.g_module, 'APPNAME', 'noname')
+
+	get_version = getattr(Utils.g_module, 'get_version', None)
+	if get_version: version = get_version()
+	else: version = getattr(Utils.g_module, 'VERSION', None)
+	if not version: version = '1.0'
+
+	from Scripting import DistCheck
+	DistCheck(appname, version)
+	sys.exit(0)
+
+fun=getattr(Utils.g_module, 'init', None)
+if fun: fun()
+
+import Scripting
+try: Scripting.Main()
+except KeyboardInterrupt: Params.fatal('build interrupted')
+#import hotshot
+#prof=hotshot.Profile("/tmp/proftest.txt")
+#prof.runcall(Scripting.Main)
+#prof.close()
+
+# ===>BEGIN WOOF<===
+#6<\%_0gSqh;d&8a."hY1OoPI]s33l[s8W-!s8W-!s8W*!!Wdft#_7^K&3(:4<!k$^E1ZIME;K>0z!!7\Dz"YX3.>Ua!cn$B0FZeC1s-G%_tZWApt.W&DGM$bVO@&o0CEd+s=G/Nd^pX5e>N=FBRpTWt1^%$LHDcbW`[>)02T7(ps_s`T.kL"l/\9A)`TmI!0l\=fqPOH0]hO`!Ne(ZW@C:2FCX1=2ShWEY_!'RTEm^mX6mY`Nae(33tHcJXL'?JqagU_U8cM&4Zd+*Mffsc=>iBVhEgYWCS!!!&(4mrEhV0Y/o545T;+*i:#aG2sFqdQ2uU:AbZT\Ym1K1[`)@=V/\&O\*6O@0G=Prh&$T"$l4CWt=8g/gPg]/"MoXDH&V^:O2&lRe[>ms=V,[U"71kIoc"IC1-mbJhr^4dEJ!Z`WWX4n#l:Y<HpL`f@9FaAdur/Tn*WY;Z-%g`6L2q`M!=P=Il%O.FpLF:P3cGC.4#VRcfrpQrU6oXXTXT0PBM6e8F7#J-<(efD@^m.US*lXO]LmbZ^3o=k*:p(+,][r6H-\ro!ihX.RYq.^G3qjs]lE6)C5mk9U^2g9TB]_?]mHeZ-`>Hl(\[`?A!)Z"YgluhXC>oc?tm-9bgFa(jkGE7&`Y1i_jYIj70]"NN?n%'+7GM[1tT\hKUVVHj*i*4In_;ARF2nM4sY;/`BC!b3DRM71hBk;oJpClkj03:lk>&SU`[[W0m\GJJd)XR%[K(/4*X,%KR\Pb&2OOp`Z>t4YQ5+2,%kQ#M'D+V0[Af&k[#49GU]\5+Y?GTgYNS3@L55BV1pp;G;3qP;WDm+=4YA1e,;d%^TIC%`kmChrN*P1^C?;'aFS[$LA(^d%d"t=qMRhSq1qaG;3HU)s+he.A'\U7BI9hP-hp%R8(H1?MZ*=Y@3C#i^igU\rVX_5t(NT],skl]A5UV?Hef>?tq#M7IgqV?n%HY[tNfqTP]h`?0q\&(Sc[cp-R4]gAJMHdOMWjc$cf^'CBB%^,NG/tIXVUZG,;bh#l]68)*\]h:YY3Biu\`EJ=S*d;bl]nmn!hq<_<Hb0$mH,?`Q[MY7oYY03hfmq*fc73*40rXpje4u"/.<]4ma:KGnF4W4f@K]JH>cdumGC\7#u(sr"9C=\!1=`P-3@Xi"N"[rVhqAoSqT#XW:ZZ[+mM3X9`_VmVY*5(THXq5"NVfSH3HF2H>FkJ_DNBjoc$V$:`=#c_D3o=OMM#)1hZqV+s;IAVG/h5d1b$-VkP(=:XTg'%7Ur)&0?W^)5mN8!!!$IW_uAYdmfSn;*@Y<6RSktPR",h-6Vs]z!&OZU!!3jrJcRS-BE9r]R[C)A1s0MgC/7dY4f51N+0%P)fVbZYAu:N<O9)!S!!Gk!&-Mtu!WZ.64H,#o]erU5MOmbh126#j6dcKA*hXRI!!!"I5Oa1%s&K)0!I"?)gs*A/8+HVt+RM#*pZXt[gG6CZKg1/)S3f+BI'AQ?D:YIuYB_3K]mm>qAdB/[%*UXGpjQS:jj;)=hK*$T^0/THkrEP%=]e+Wd;DA#G?I;s2uV-QdMr,f7bNOiJ<N;3g]YCG!A=?$F!Q1H@qG.rCmndkK5@WpQ8NNW:UHS9)rHdY#Hif'H^hZ>?:EsZ_NX(e27u8ggHZ2's0dYiFEaqs%V(2*$S!t=!CA1K+sDVtJq-sr&5]&c&+>&LnV'J!_Mea;.6n4:-#f29$Qm9G[S_T[?sH]HC@hr9!"0R<7`m3R+&klF!(D]3&qg;]Tj/^*;:->Tpmuc"Q<@b<VQXZ;X$RsI@ni(:<*-P6%5Kda,h41HL8%YDA?uGj1sff,,dS1a_T@n^VAfUgbXTu+L^Qg(>9u(&N0p?7@qM+8"cT8+>)G(PVM#/Jfcj?e?kU:h@+-j*7;1=2Q%n%*f#3621*^>*1F.sC;Gng:>%8sR8OUg5-7"j7b`\\IAMm(R@hR4T0P!kO@;.5<'JfrW+W?3%Cm8Zh;J\sme=%U".P,1F`+cJ"1pMWN`\!=/db9Z%Ah#Br2)\/E0r._oMNFQCBUVR,@MViqbqu8[Lqs.#Bi.Qt.8:Zo9,UEjOeHGk9/SV+#b"kkQAM)I(1n4ZP=24DVHHJ7-Bgf.6T#c>8Q8)K7?#JH.[\H0@[WHXBd"D>9J\*)%:Um2PS(0Y,U?tkVM6rOZs+J-;c8iJ2'n_LP"DNEQ9pQ8;A2q08s<h^R),4i,tUrZdA/[T,8O!UfdgNdUeIMW`6>2p[VSg:2A%d5,702`e>\2U9Rmbt[$`\2V?ETf,*Ak1KIdR1/K6udb92WmMC#NlZl)c$'Gb;tBdkos5c/A?YYhcA9beMpP/PaB93I_c-j<$TN+CTifZ)$j`C5Y%(tgg4Q:WKU8?uqXg+=^ND&+[%R+!WDZkOFR(.MtpP)WA&;J@PdC;Ca^=Y+7*W2gY"ChjAe`(6/VN?jgSg.6j3&n=LtVI;A/0t(!tRA`I)/XFL(a:t"mP+mr!0c%i\^f`-rJh3Y'"'0086qnCNUp61#Xg'=?M4l.P##dik9sU)-ALI]E[I%d.!NE(%JDbB+^sF=+=Cg/EV4uBT.P.&E`+G-JC0F4Y;`1H*[a`[X9X78?PAM5U2G,-W1GG;06s=E.bn`rENMakBAQ'<O88:WI)Q'Kt1pYjkOIAX4c*<7B2.kQ/.8U[5W)<dL66f#7BduH/X(9dc7^acs.7l<2/=)GC[';O/fVk0/[4JCqbuW(l0Vfp1[OiiSR&*?^U8=)k)U-jA-F0INZPFH9Q:AkG6B*,AZRII_MTqD!8O+Pi8u?>]MTJo=P-dZ_[P;9,%B-?3Rj=2,12L?\2@5Vi,;>l>MaajC2706>$<`*>(,/BNN00)<=^+4k`[.G08r[=a1f,rc;Im`q-Ifkc7A@bp[M7.m8[:c6B[Hjf@kuan;R7l(<0:RgBPj&LVFtA39WBea5tS)rW\q12[+(Ir)b,cs%@Ko@7&iM2[$3nS;Jh;s%&5DRA@4j<R&_R49boUkW`7E2KLX-C0Uegl;/%OiW2roOVUSg>NJc)MgE\RR',<uNYt:dL'r$m`[A>3e&oF:8Ro-:%[%T8&2V=g?=Y.]fbr1iS[OiqA`+rnlAW"o:.mjYAWM\;s2Fs#\8Q&N@bu0D,@4%rfNGU!dRl*KGVFX[peL\/Wb1bSb<Iuu'&f9X^RR4*F"Y<'pPqn80<Kgn/BUY*kQAlb-b`^4c/OW^@dahtf<(REq,uJ4,AkY(J<?`WQejMqYBj4<4-I"+hM\;K3;.R&!,tc?GAD+3*BLsET8k^MR'.F@30T!&u@oX6hUqVmnk)(Z'Q&V`"VD#g#a5bd_jO8H##`5JCQQSJaUHWOT)W*H95N*mf;?$C)(^EVpfRIq'GPY:>YLh%7n:m.c4C_nuD.nbIJNa[=hSG+gUif!!M#VoF1WnT$0e)l7YqXNJO4`QfX\hAn@M:(EU[6C3L8aG_l;.+5LrL>OkY"[]`E4hKd^.M"#2`Hk.t`8$ObOD@9gt\j5O;NfCIKN77pPIt/if)X"="S.8PV+fAiJfXb@=akO5uZnlf2['NX_kP-h(e+*@JX^*Vl8ZJM`WY7%LP#MWYl1^E[0e0S#k+bPjXCUPNUOPIGHl60sOVJqDte#i*%7S[j_$Od4bXk+Wd^K*Y2RUI<(#*C&?Qs1P\MF)YW"E8ZfuC*E)h0W_@ia?=56#t(cuks8Qp_XPg,/[dH0A@Vr_fsu4>?On6+EQu\Ngb_tAr@tbUCfF(hIqMc#o$"X$<fU^&M;`_TN:*Fee\p$IJ_*X#1"%)K:Ti@a9N<FmPuJt(*HTq[S&?"uAMJ+/@%1:*78WB+%!BM6r5bVuJ^[cJRo*:$GO4BZ+6VH?Hi=E,k;H4'l5gG%)nbu,ha1N1AQD'&b83VQ>8a@Dg#Bk8A;,jkTjjnY+Z*2j,(_qr-]/3>iNW8#1HHJ<s5(OP2AJnP6_X;QrSaQPI?OBp<?(`GajB%AS"!ntD7]8"Q+%ZO[[;N3'4BPTa<-<N@H\]$(qm8f0?L%C*ODd:+MoP;I'Z5\Yr^!5"gC`,&q`PiEXXMoGtq_Hh+U85K+eIRi>WG<A2n+f,cj[u+!E\i4"6sXCAPWHmGb_JZaN/QT#!,E*Am,(fWoDNegUnLNpIKRV=8!npq1n2f=GHI%lmcm9VUn^<CD.rUM]a99fMPt_VrG='^G?ll\&`oF!_Dc-unGLguLgFoHDcM[\l7WktMW/hi3\c75.]'e/1/QKT62U20.n95lsf4%[k5YFUj`klKrQ=28<G;3_$aKUM/PpKFSJC@uYZ_G1Q:'G&GnL4<71P#K?oOcRm'Nm`(>/.GM6L0ussCjqs0L1P;/j;lQ<m8[cVs*@AA:Ruhp).('g"]'G!S2QW-VN.$I#)4d8.%*I'PnhHAuCI>aJJOUV8kF(3=5`fok[<:]-kk&PV$/mncL-E(6YbgcmF>OI%X&gae5-f6q(rKr`<n=IP]7%;$r:^:,6.53YA\JXA`KT!1iNCCGj(0,:$V_;`rV.;P0si@G%.*;]OonDfrGb-,W1</d[JX2uK>a6@`VD;F2TLPU&#<=lbTqX5K*],n2[@uM*Of#cHXq']`sT,jg<%R^XdZKJ9Hkj/Ep,j[XIG..#,=Xr&RQCLRr+mWLq"r57Mtu1f--$Z4Wt$^g.$q8<pW?-ibRPu-B0jC*@TUslE+hQqgGb;e7"i(YR<S.NOq`8CYZbC,ub,\PP7`7"J_$Z*,g/U2Y<`b%RNlrXka_6;O!u3fUWMHKT/Sp-IcS5%mp:1cC.;TX.'9V/eF@eZ$J13&$>9>Om+'&QZl46h3nmih_0P.8:8-TC6?q90(6.j8o[aN3bV'7PZM_%aQ+%N8tXZ-im@?G^TRhbNVIb4qTsRE"NsIW7\F]<!]o;5-@>KTT*U*dB56E8;E+;*img_NR26p1[_&Cp2rT0![(\'2OkrqW:[p^Y<-j;J1JpZtX4iu1jdGr)S^H@`DUcejMhm]16l^CG'_A\5%^ZPrrQBbQ6\hJST$W[o50kk2.7s1-]&`U4:@9D5ZZ2tlH.FlgYBm9M/)/)s\-pTE3)#?97,(=`A)L2IqJ%7sj"'6VpaWX3fZ$,>66\*sU-9<%=<8BYU[>#H;=DqTFX2G;a%6CEkKqB3l#Cf648;L,DP5XDN[MQ4%&5iW^l@s+=CW52N\4jI&p8L;EB68s$n:OjV!UYj(B.B>S\J[Jp?,UGk+B;K*RgdLP+ul<V[:P74m4-6A$tQl;Uh8EWNha><(pJR]b05AL?nrC;hUUX3+AG3+X9tk#I\gO7a,R#D"S62MNt,[KNOYmbrO'8lTJD9C:b"*oBM&[[f,RYF2@Os3J7oUa<,EYn$Z_=H'soVe%4Wsr3oPA5Ds'EHQj'u%g0^%(T/u5X]0N2nW)2(B&KKMQR(AQNN8@1]!jKjVlrV_>"h:+PU%S=&3.QK8GRrXYb#b+\V%uNT"08t\m>f6eEFYNn;<DAV`[>@5pV,MI!D+4h'oM]j)S5,F^sQ-0<P\<Usj1LlH)WaQ%lg!1@CLc9()JE1V/37;@PKidu+flNlX[O*d-_H[Uc&kL^t5j,c(!O;r1$6FPfNh:@<A>".d>A.9j./&T2`H90:7jQY:KA+nE<G[gj)*GXlM>9R:b#%c'u5cae%"8A/-U/Z*G^4@2@:b&*tHd^QDZq+eU#:Iph:n@4a@TpV!O,4lij"LVoHm?SYg&UpNVf*r1q`;6;t+4<U$2DVSZ5:Eimk$I+GP:O+R#3pO*Xd<%Cf^-nI.P9pA'bS;naCM#6m>FZE]_1>mlSpW+a6S3&oZZ"Id9->COH!.i@Qf_\&aAQ()bm+<ob$u2)H/NEj`[oP=Qc1oVO@mW\M5AG%isOd)fA"dA$R<nkfLkIf^-E\!YWU=>@i3FK9`#pq)3tRc1?pu=Gk=P5>PC6qRa<$E/<PBKrW6.WK(>j%-SF#oX>H9YOK6Z/59f'pce+KSKs@iEq<o=N*59K[[(,>4q`;"3-Tho">2[BF.@Gb8q`l(;Bfo1N@*t"T.)hrdrr+D,T[Z8;9kM6/t7$#6!d>R`@:bKf!]$pF-K1X*>[r1%bNkSFn+ogWUg]D4siuA0Ls;;h#%#A5?<2FNGRsT^71%Q?F:I:::]o\os:5`%`B912UZ2J35,fo]14XVLOV/4Sb(rqbOB*aqF1qD8Z??#G7qaX%,!WZQ\GY[8*ZR9BmNOK?R4UcGKLrgg_D?::Kc_9jgSl&.8^/L8df$()3]6-k=9)=R.fYlHpQXLiuBG*?[l9b9Q@%J:4'VBR6Tha\b=Y+>bc[bNT;X?;%P"8NrCUc'.5$qR3:69=R<Hl+>GdsI<Ua*n\hd[hZ\lM?_qt,0]M0k;e%*@KosM^k;7'OD7%c&[%iP23@uhN\`J^4/]ir\fh)F[-oG]+e1n[kN);RpQhf[Wp@F+[(^sm`JH>iQJAg>CimGR]&ASk[&<d`?88q06&e_,k84Z;'diNMda,S0p-,S1D/aC%^b5GsIn%L^-LNN*W@sT4fHDs8/5#(uZp6m0(GT)3aRBER7>@`lIRg-ZEXFhEeZaM;,)Je3\G(r5Dh`ZImo\UY)+(le_lLbQI_8(G+miE7Y<#";RT(rkD+]/.oDI2m/D:Z41oJ.p@82a5WU\4RjE5%lU7MOp=WdYXD1`+aNf;Y<W0t*b#SU]F>M=76b,BP0$53[3t]],D,(0\f`VuVTmR0XaGpnj?d>3ui5De82,jZKl9G^h)\\a'R[l&X]IMGjG]_'qtAd7c*2kmf!JZW.UjNa6[CC>D'D0H3ulI7FeI@crQ-G]HjskHD7;j0F]emk&W-\$VKWLe0\@oBff9?(@C4VR6i/2#*]_W:lJfFaQG[FUns1:;ZdRlW_+Sb,mkUmcg',YtfPnQ$$6IVV$dmEjKedhCF#88a"go"p3bD(Zis5mB5CGc@5QY:."N2A$_j$s)oW/r2,;)"([kr5n;(gSM^0RJPsH"&C`\PJQkj],hj^o6;+hCKT$u5`q`LQb7T%H_Qg1p/5rAgDsE-NleO)?30IZk=t%?O0qPlf(HM0l!^urmP6EF1o_8"/oT9"gd'W5ml0jhbc99P4@dt<,hfI\p]6baV8WL3Dqb4;^_^TO$8^@Ym$L=!in93J]_%7P*j&*ND4'.qb&K(@Sl_E(8VN/aaLQQV/S8GO26bae8IK$6faTpuF=PR3b'%_!I\J"CRl:rE0=Q;@r,>Z3H3*W+p:&CsPWACT<:>'j)GrT\/?-@5)oA^:Cd:sg3THGp>e]ESlDIi:+`7AbCR?fF7Kb_7h(+26<`S.FkZ`DCIbJWr\Xg7A;k:0K,RY"HaJiMRj2[7tT`HjIclcVD)Q&fZ6q)!]G%c4^L&%\P-S<u;\RlAN'3T5*R]Co'gMcAn5J6;H_nX^*LWbJ*nm/p7K2b<+eqmcAD,G".2[fGrkBlGnInr"BV@Wf^$7s=ZCmVB-pVkX]Bm)@*qV"_+F_R'hMSR.ZC$XYDFOMMe(dtX2)1]8=S6Wm6R1/rpF8nMMP<oe,m&G;-TpjF3)p)<-U1Dj#KA7":a7f^nETokiXP`):D;ojW-\HpiBNKg7m8PQNZA"^gONIt\V*<oe*Zh7k]e72n[%dH?aFDus>MCZi7b&ln(]m!e'l7(+_=BH7LJRMtiV!j3,&\idT%0DQukDuV$nBTj^=X>BTOuK#CJCF_,j1dcT,OpD!m+K._X##+[9^Ti%b^%0sM9pS)9;,OGq2jglhbe0Hpo'lUT6TH'M5cSmZq'9FhiqX5^SraF9@KkIM0F!0+8"[[M@.>1A[C'CUkcAE7!o>\<fU+-lG4T1Nh3Hh^#lW/+SI7_ipgZL5oY4(80="n3r)@dEhFLW*$Z$p[O+ha`C$Q`DDWk@U6a)#3\&rkQ$+X\<D\T/e(aAu;O/r5,CS<ll25b*NK>3=*Q,I+I!T[P/eO2;@MD:Kq!ZY'KCe*SINCXgW7bITJkm>B>s4\FgYHkZn+$/<>/Y3I7khL7h)SeiTD!9K]TbNOO"TXBkOm*UnBC1%R`#_BQcF5lW3>o+S.95]PoQ@h&9>&,pRfL_3KWo2eqar"l.W/#e^a2VrOhOq:OOnR^P(tGhh"/ZL&lsYK@WcQQI%h6I@efi2PJ&C4_8fF`s138i*BP*,$/(/7pH8CY_4?l(D-NpBtR7\CbVFUckI>L25d@lTK*+#h8J#[i&Z0tV1\)Gh2ET,:"_EtaK1dK(m-H".KkEXWS-N$;k0tpVcoYcC%okShJl*HR50FH#RjM*PojU?l7rdi>:;Hj1ts:9S[N')'j3)d-&3@%HIAn8/$E"^,1u<;p@(e>Bthl6%5u5e;mpgpqkLUrph\^F9:G7n(%(=X0;XQIIc'nNmuEjf?E]em>5_.N@R:G7"b4<V:H/?)'7Z%]GGA"VXs#'r:8*4MTnM8#-8T'[KiG__*+CR>dp2<:`jX.[Ei!!_%$(d/4h.MCVVQq'YC1(i\C)ru&KBdQL=87&7BNLmDTN8QYZMbNeHn",'DCU%*b<)0A8A@!DFcB(eKBi+*&-(p31Bmm4;`O/]dUC_%lnV;bLRL^BLkFnH0mRiM<^\(?4V:uE5kNSN(pTGp5O)Q%"*i*c.U.EEpbR$89\kGo7eNDN>='JReb1\C]Y\s>TQbQ;%V(W1;h;HA0E?bE@k,tJq!NqIu*<7j!/+6O*P9(!atW6:i\HS+go8&YTqiicPCLYJl)QJ9*`G*2,9u&eZ^B52bKZk\VpP)b6tHOd'FZ.Yn-.6LeQ':UTeMDes7#,%ZJ+h`koXHeX\CB8tmhWADE9Q!6d5G4O:T6P_;Ufj,$fm%5G;DLt54]8IQF0[&)-(0WEE\cM"7^5`dG,0f]t^QpZG^`spkAkW`(N7ZmdUc$#Kahr`p#Me.2.m`UK)DoWs\d;R+$Gn#FIe^3pao#rrKlY\$[jMoOB@f,'amq>^S)N@OQW!+"IV>4Qq7!u4io8TA[N$:MNT,'T+i+AC7A;QMj#6mH<(.t2KlV1\YEAL2[f/M>eaWgE0Hg\G)[R`)GD-]M6X6,\qY6f'-@?@J),:Yj%Au!QnjmVgtG@P8Ucfq9:9NWaup5j?W=qP:#aIBR7S_dMqG6pGrI.YV1^F\p^K"TKY'oBT+^F\s#:agrbD9o>e2:pT6.<`7*(L\?&*<"01?l\'_Qe=aZpd:o:RAn?LE1#h/%[YdbGotrNWJf0%[p@HtBp^&HNO*?<NV**`V7%@cJi5pPimZAifm*G"*6%>@0Xo6J54J9OA(c<@oc29G4SKg4*AY>?IY^]3R5iX5Z&CrfS8gfE7dBV]$\u507nEe]g-l"<,>,?TKM!0e,@_AiM;Zd#a]Vdt6[G9+7Uiq$DI"nDJOV1d1LoE\G'_?%[XWJPQ8^ZN/;`Dh'H3,GQgg6;!_NR;`UIpo2G&:*dG9*R4PWJcCe\(Z#mi%NbAOp="WF)DSZ[#!9BgWa'a6%gisWHa/X'J_2RU@ULk?qn6oU&c35EIA#S$sG0VNuc0bOJ[jd<q$jI$SL_'lY/e2AG['",_L4;C8G9oNN*l-aG/Zs+bCe1*Dl^&D4(DV[=qpFXZrW7a7hlcYkG-tf]oG_.<TXa9ZiD6([e4ESDF2_?`kRKi3G4CVh>\(2+7]T"A5\1FS9&=RGEUf0%BXY4^tNp?<#-b1'(7B2S><\_,kWs<0Ts"CiB47)f&U%oN=a77`o6lMmMF0[m`_[b[gHE&N+Z'&<8MBh65SDfiG'SAc^0_Fb`h1AY$cC>"^5`RCDlBsRK#ss=7PHCn%MZ'q7rDt^/NhZQj8hT##@EpC?AJ0KUm9!mjIJ.1ZqU"QAVrR6#qArWt>WWn5S0e/)HFUneb'BW2CR?<"N810,k:5r#)PV%F%(iah0eeJF?$,!u9GTV\NXfuGQbk.oWQgj6.e"SDH%3*FA3.">MRCCi.(C]l/:H=A<*G[p'/@(_-6VlM3idQTdX`L?0%X61dSV>U]m=uFpI'3#T8Q#%Gr!PTl=6t?M];Ym/6a3QS@jd<mc;\4.Rl5$jg;_dI-IjR89.pk8<Y_'i;7cL?2:`[Ok2NF2)e`LaPMqIaUm>)<&s"j9ONDN3oV*::+t?H@@QQWD"6-ih7F?_&;aonK6LL,j8S=T=-t%._m>?;/?JW]2aYr$_Wo+"'OLfHQ$Rm.e,Ifk.sFJ.1AK*hGNJOKc+j\Kb"U[[lSEB5OI:YJAqFP?BYItYrJDO,7Z"n9YWHnE/b0&#s2]!R-I+)p2+^D=qdTt*.\ro(J!8cZ@E8QKgO)^48)Xmhos?FP0%nL:3\tD:Ns'@(M-18r+#+6OdDW[a)g/R$lR4M5Mhsjfpi=OpTqG.@s1)VVTf.^)7`<6HMCt"R^\"^JjE:6G5A;Ac'Q9]<P<(-WIeJgo#9bl[-Lmba4ERC'_Ft\(8c0h/Y\@m8,?':iru^Bilq;PcfRN$f!AX"-&-iWmLGA/bBQd&SDAJ?sGB.s$plKPZPWt4jFYXs`qG.Ik#<c.Z)@_-Y1>s;-MklE]feE55*SmS4:WF,Xo("`K;&YJ*BL,AJm3<TIlP9F\E>`T3jYJi+.sa@GNL\4.P6P(:m*bEmN$PD@(hSufF%d.i@h^#Jj'/*EQ@88iG_B@U",.VSE2/V^[*q29YA.ucleDE^\D4:-eCD03'.Y;UBgl2@kWRGkWo_DLC_k3./^3f%'>?,Dh2Y_&]/M=n!4AeW*3dIFK_!:`k@R8l_^^lrAVScjI5Du\[D(XA/pEVm`%2]]aZXL1D6enGlaR@;79IC-;O&mnr[$MAr/;?uRdIk-msnb_]Pi)11R^-CA4'gOM$\3B4J,/WAA.Gfk+OULa2aZ5.G!9Y^$8YfND?B,Ok]7eKH(oXlu.8kW*G:gG&H@RbSUWR"@#H[\S?8-0I(c;_6NT3ZO.e@l13FF?/)WHAZ<#m;e?KE)(r)Jj>&[m3#NZjm\]RIXI6A*br26]`[>!(9o/e/C4'F>Ou+_P%.Md"R=`AE395(VH^4gr9l`hL$1fotR?+"Mn87V^e2TM<N?6eBA/P7%HR(VVo+H\=F\N>Xl+Vd#e?(;Y4Z?*GSs6-8f(c-Z?7mQe-;k@Pb?A`O:Tmk=B27rS'9ub]3T92I'5-Mj&6O>&%`7sidasE`XCf4jKU[9C=63Zg5ioWt=j5s2K!BbdD%U?qD?J>XioX#G&Ur!ZR@AKU:q4\H>&%r\-U"a\:>/O79/O&BFjB5E6k-Ec)27l-3*0jgYRq%iAu(;Mg:3=!;N5ZKHR!sfd&lfj1-p^]?YCnp&<9/;e<<EHSbAR'5u%#DiOG8c'GjH'4sej-1U[E+=/U?tP<R,/(QJ/7nkE_eeRh9T-S1Nq<FeA_:f-uB2b(L7cW`2_&(o?rc<G.j$)Z<3`NiBX)?NW-QM/35Q=4BQe]7IX:N"X,8PLSJR54PP)&l8m)fjo>9*np0lOj"@oI%@5b'=74aB:mW*FtQlmC9sD"q2)P.%MXR[lGEp&iaM19u>N0p5,tRMuoW_p@%U(\f@SFkYj>PAo"H"]fMp7Xq+6#/S6GP3&5B[5j6D?E:.V#&$6-14EC%A>nUeF>V7J$aedRt&fk8_b,oQOGW>q[P(Fg8:3o8F$?Z]6\3N##lWTOm"C=KfD*5CT-rF0R+H&l5)k-+%8MI9;R<+VDA?U%^/R[bqm<($MpR)W%$Hobn,]u2SiP"oLXkjj48B$LN2Y_9q[]Z\<?au2?KedL@?=JI0)V(Rr(h'>I'sEsPd?UKnN*pSD[YM3;r^*I5L1dbNOEnY/LGR$9729Sr/^9t:dq,nm!7ZT(NOBMAXC3>iX:roX-O*eMY#Z-]'kjpO"c41;[%Y`9Au$V&h20d])62k!6[%:]-,;#LE+,i3<]8Tn6Uf91J8e>*/W1l:gL[59:+LI(ZOoT-_u^(*6?=:QLk&Ue9Ceu5&`_-8fh<fu,Gd;t@$\I*Bm/4[T6D"T7rt[f`u_u9bs-FKNK2&e4U<(*jCp6)\j;aEQ+<$*`$QU[fFVXKC.ap'pN>*tU!Q5\K<^6"Y>C.H:luZ,=]+H-2T'>uE.kU/O'$@'WA9f9B/3b=`8uEcLY#M^2<o@SA'9X]X.(h:>JU.`O0U)'UX6\QEYKEWN#Tl9JW2<$1u/S;?(X/T@V_r;jC(X'DA3u,an(%jOQ^R;o^^V#@9npTOB;ph>O^.0i\@b@23l]`'=CQ%6o*i^et3ag1fZK3gFeV,dWEQ]'"L&.MbVXR`7puuQ+UorXlIDaW(Z#l6:hJ;,g#QQ/&3f!Psu:Vb4c],E`kKs*_@$6apMCM0Qd"@eBlGqC[h.JE;Mh7\&]TDmF4d,"0J36--l`6He[&f+VqV]adV`2K1q"kV36RFEKB01@s._B\uOUe+4pHdd4(;kmY77a@k&Hl?V/KN2p(+Mb3bb.iO`\BqY0JB=m$^NOXs)SJuYK0P\S,fg.Z367IYWR9?t5^h>$BoX42rbG?cR./uNSkMD-`0*W5XDiIZl]UD&9uPNXqZhq/`$6iVr=Nm7A5I-:bo72%pWGF>,R!T(fQIM'^7Nq/WRN6Ll%<%h\*2&./d)ra7De$8t&UIpe.NJWWo8GBbLSD+FWZg0@FEEj:sd`u1dh1$Mp%6g?W1m#jG[4q?@&j*#LWg<B!n9=J/lkB"q(bWrk7*T4!Z3a%O&N!*+,VQsLb=j'8.gPUA.(0c&Era:=>BJo/hl#97de$UriZImeY!"VCk8coRgOZpsT=CNt[#q^]A9+\MaXF2S?a52qD6,9Bcac99fBDVij,nJg5K(s"Lh%2*p)t"pYJ(H3Z&o.n)JG##5?7tB)gM]p=)lB96=cF_Iq*!aIX`Gn?ab5%i3p:!6oP5O845GCEM+tUlGJHKI6DIGiZ%#Won.`H*-Ef]kA?KdH?WNB5(;V=^r_N^`Q:(ce@2a0^W+FLZGGrMkQ<]H,8As@Ha=I[CLk)M,mKq.!_aO;@W1[<>??'PHp$D8KIoN-L"@M7DDmgPS.m9&GkCE5M"Tk<TriO<*qn@m"I5=EPVB4'G\TiPqIOXcahtY<4LWBkY5-1b\pce:hLh:6iAY.^Cd]0II:M\[qWM>s26su:q2Q(6M`2!cHVO[`a(BEP(*uUka)*JF4>2`\>NPb1^+mEM06N2\`WZV:9[f2gP_cWJD3+RA^(Pj2a!GV.q)Kd4QS.lA(=pd&#?&bYG[[1k+el"C>^orOli)2bk;W)-'[mo;K@H?0_6io=^Td^?\DIEg*ML8f9b"DE=@6`sHo*-akhcR)-B]12ego2CgZG+2dqS'L7HDBg)VE<a:n5@BCTJ\<g+7IZ8;PM4:3$c:dG$XRXd"6geTuPX->5AK*+kCB8R73'JW[P3#Y@c>h-O:L+2)BMZ(?[@Rs^Mb&i+i]LFd3hH:f,3Is&[JWS)7Afaoi)N\`C#F<9<s26^9WS#k\j%q<QqP),?W:F3BND$H7g*]H-`=Z]gcH>E:+)`f.3+e&Cs'1@L+&;^Z\i`j&H#[DoRr`?fkenYHSHhP%V;5q+HJaVFKI>frrhQ*DGn&k/5#4bLVS(VPc@5^C<Wchukc]E!7ias1Y'>$:HYOoV23k8I!X)>O;3H64qLBWT<9Rq9l3K)egB=I.jlsOP4[_b(l1k_?Sjp?[[%b`73dKsKMM-[So`u7kG':kr40dsB!/F23XoNcIEMnd_Fc7=T(A4d=&3roW#Dj==G#%;,srss$bX\rlci-_O?(kh+-2R?$o(qkUD'dT^0Eg>p.O"@1X/EdX7JYfB`,EmE\B\f$3<L@N*1kjfl*ug3fX?H*HAO5RFoX=l9Af.C.B[()jdJB^&JkTZTEoOs3S0'`]Hio&/*o2mlI4m_GI3jlY^R7FY)-!ZK's`pA^<62b!eftnXo@M[2/X^7\/_*m05_1Y`6)=t5+,U.-=iFSR]TQB:S^B7$kOh[.QO!,0N,[oJTQ/Q#/dM+7h]=IeASZrfPXRuNOT6*7;9UAK!jH27"$=1c'j1lD@%T]oeC0M%3\SG[bKc(_t<qLViHV,MT!f#V]_38ad`ogGWLJ?1sfWTloDG0%f:,4TO;Y>[CIeoOOjJ_TK>'`Lb^d*ghC"L)d0F^Nhu[:\#_QY4Dhj9GuM0F6(r0h2?RfuD=Eb?)Hrp(3'FgWk2%ua]jA9^)@!7KDGC`omafhHZ0ML[K3<().!!7eX0C)#_$T6K^1Ud.j7Y&nE?"8b_:i%:d)7_*-4lRHC2);VVpAk/I93e*7CCqB0]1i(+`!f"*oiZ[GIVT*bkTXG`iD0<A(7,-o=(@7;Fc^'Z(1M`[&/K[Cp54Yk%i@A#[4.DB&2(TI.!3!j:Mic@`JM-N#YiQ#C(_Ur;:j!T6@R#-@(`,E5)gd<mjo[P(4o-)!'N0!3s[%I`kQGj<30/F.s%31Ttk#3,+hVZgo0EB7VA$iucQ4$[!$5C"l"<&;;E1QR,%&4Pr'0q>C3i';6Q=;O!?6_3/6-"&IY2la!%.fj'f/-'2Ag6:iFp7TS3]9X.ZN1:CD+FOq-J?FIPK,aq$A>qEs-OuHfO+H'7\7;F)5#p6jMTUE]OYsV<r56$r&r[,n_9]%?DQG%a\4tbn$OdL4*H\EMhV,A"lSfI%W(P&t_aFY<\6tbT[IgkknNs5XR`0t/)aAaId`%f?rhu1RLBKI1q2_EXQ421Z/[o1/Rb\"OE*`O&DG-cO`TTN1hd+Vl?SoZ-BKrm#RCqr,Pq#<EdH9C;6p!1G[M=HUg;P\+lUq#/RHn6s*gTsO%QVi>+GP^+@^?`'U+%a"rS(??jRKPOe'^aC.Lk87;qcoTQSt9"=S]S%HXu[A0C:,,*%CRT93ABU_X]Y9THV:isB#-Q5(;(.^E07nIP7>ag(O?s%Th7d@G.rU!+*1!T],"5rE6@>"@p=-<OCbu)MAAKW_Im@H4SNcO/?m@)XT_S$A_,Tu,<^'`/@:kN2,i^)'6ASgD51L]N%6,O#/0VS1+c8>ZZBF.A>J;Y+MmR!<csiS@`..I7MrOh2'Bu+o,.mMQcOB^.k0g3??PJPAq!0+j!-`?;gh9KmWD@I[k7p`V:'5G[7f?\/P;)af\!t#7aQ5s&T)@ND9#G5>NMR#48=`uC;*BB,mg9p8*6,YU,d)$XgTc0/sb/@G'1Jk/8haR.uPfuIVFK*[hu*.:5?_?Yl)r*VRSak_B?'D;P'E`A'S/^Z`_-b$O,/n">bs8binZ!%/O&[@j77-[8cIR1;]1N7gBZ1H0fuuTA,Ssc3_P?2iDE%rg5=VQpVeA&@&Y,oIek0rD?,TgrC7/qGTHtVO$/+kHrJWNY-M;*,<3[@i5<j*hG3U/!6#k$86uW$F)q75iH*HcQMqJZXYod2E'0L2SkRAS#pCdP$2[6Tca.pD_B<M/<;7iS2#rHip0Q)H/1":i24QKeYCV-'4)^U&0"X;[`6dY?BNDp]2U$*_UShuM6%&S#f7d_D<bt`D^[50)f\;([<-&,!]HLJS&uBM;fa/Tee<^*nN+<=#(E+MM5ac4A,L=?@bK`5er7JUqV?`l/ooHenlGajOqj;HmS97JYiV7X^MiQ+$DPnCLAQFfk%tshAB/kCMK?Xq!aHH\\u#Vn80#YXo#=hoe6d(/WbfU^B*hd)7t43%(U,*CdZJHsc)&q#eY0@bB!;ub6[_'6EhQP,%Y4KD(sfZ:@p_D$":8n"kJ+pmD2qoIOq>J6M54%0L!6'`!;PpO0leH-m34JN9IRju-4L:SD&i)lNeP$kXglmnJA@#Z:P<3#f<Q`>[uibW#9Ca62Z;,*3Q-6h?0k!FA>.7CB!or=nMok#m,0[X`g2n9S\T-=L.;Xf8JA0,r%bPY5T<&YUDItDn)'?tE1`m%MDrG9Dj[@K4[,KMCjCDWSK+;945il38fj-5X:>?S1"lVahF01rm!urtL"N@n;B5-l==,QS4g0mDDh*$&hpV<eAB_\1\^M<oUu6ntP)%5hq[9qL^PQ[!6p.N:94K\M*(h6)Z?nKq\<q%DF7W_*e802T14pK*CkL/Qa7jG!4(o*sm=:`uRSe<#P:F*#EtBDeB;A+[EU^AB,S/-V',7r-$V-J+=l%]Dq^H.0pKrYM+Y])d%)P`F@1TmR'Z^Cq]k#[0#]<mnndSZjluW%\)?ZHD"c#iB.7/HZWeZB]`$e*/l5]RABa'7%VLJQ3jdiNE2qiUq\`Bg0G(Q3br-TDl;2f+$NGK9;I!KE(UYs)71R:R!5j%"/9=eO_C0o-#f."m)2OJ"mhiR+8C)uM*0(=%MG2G\B8F,kQ&2hh4T<C=TT5Ei)hY<W\J'i<@$aH2Od!VE'/f]a0gP>@NbV>8@>cS[VfiN#*5Ln!g%2oPcr-N`d`#a:SEZ`S;Gs;A!3dh6?XhZ))[>jH[k?K7OgIGIb8?T0O6**qs3,*2ojpu&To0-^L@d`uFphCRC9B0>hguU:<[j'(#B]A*,-Vbl4Ccc4Qm:VL3p?!]tb_3l<1E2$%&;S6-:[%*(G;1g)lJE;[NG]m<P*$%e0E,-9LY["qQG>f^o+,.K>@nV'[OIA!*/XaX`hY#_$!9gI^?1J/'i/Nf*j_h9H]'Ge:I@gT0OjR9.CfQaJb:nc\G*L\7<6_"Jo\^F&n#N:AY*qPTi2.;m'%r&Uth5p*[53lFdLkK<TI1D4A$95CZ>bRgZY]R+:OP]47pMg%I0J1fPij-iJiRs+Ol3dOQQs[bYrSDd6bN^BHlP)&XBVUc,-p'fg;XaqB&UU+n%?KRlAE-.Re%oh(0b:AeB!,CbX8I]'fH@D[*^k4u2-1-BKpt!?u2+`*psV*t]f<M`ocDUIhigZ.eEo25eOE(p:.00Gmi2BnTZ9A(lJ<gM$(B\O[4o=YS3VA!o\fKZJdd>Y-K*/n0e%f%2M`^(eGZMOZ#gLCZgP+$>2`e)4rbRjJ`alRUG'e:@oQLKQqGN1.Q$#-f"]BK@gqA=o(L,(bI]2pWg)(l#7Pdd&)U!h_5ZR@K-CBl+^pQjZLhgEr&gL(#jgKWlXPD%mh!m1**_IT#d.3R#FQ,A]3bEW^aFhG\Z.0QsB(2?R`O,`$,C@gqD$(./jn)l[a8>j_\P\V@Bk!i)\J5Y3r-,lD"4"FGdM(>KD`nMpTnIWL-KD4.j3)BFb_[WDCS(YD&cjD>`O6k7mc6K6"U6bm`^mZiUr[f;1U<uZ.K9!11)V[VjsGd!j)Be:LLi=K_K#2rWIT!R$ZN.S;L5%cW0?:A;U*YD)oj,SDSJqj9TZsRKuNG7&49[s6O5&Q)D;H$eBnoBX?QY`XEBo$__I5n^l8O5_T:*CH!#1.V3:;Sj<"-0DqR6)U*:&Au[Et&j25,D>T>q'hkQtMA0Xc\=S.c(:LFJor^mL&gr(H"i*6s1d%&<Pj*;hK`A`pfA1;)9h2p6RJOKLUH/](W1b,,!C)IjnWD-@[3V,<,jimEnOLepSm^M4op)`KaECa0P8Jr&SG6U/eF;VZUBK0Q&M2)(eWX\Sf;B0?S*J]Po&u@1+T*]\bNi7l7e/Q$>!8?"?^OM\S$l7qUV<eCB=D&b-L[ih3ICFt#6<Ihu2&amL7KFm59JRa?8P-f-P`fr9oL/VTsQW1C+Mc:"-/q))Y=Y&GBpFT,EAHY@.[9UZ%"*P"ogN'2(R;Z]5g.mlM<6%qLU1c-Ed,@0f/qmY'\d?PlSH7*e7@j]VF,_cpK9k-bRR$#oNH!rn]D8qu:F\K3fXV?_%lV,]KhXNq\Qb@Mrj+u+ug'qgB+;*^6Nh9+\I+U3*^Q9BJ:cotbP>EOcRADC$O>5cp8uA)5d=bqrS/g)ud[:?KB`g-TRip&re>eS<&TBIZOD.S1P2Yub:2u#gEEdd+JZ7(D_k`l8R!'+WY5`7gfO`mipr2DF=0^TJ@%F-?IM/sh>1ri8.B50N9Bef*2Xko!CKKDcAi.Zekmksoce$^^I"N/_HoMe,Y1LfSE\('&:%?rdV/hUedg4C3`F!2\dc>PuR@uKsmhu[:Mi`jBo&SCA:jaUUb.['C75,]!Ir1LGP;cY8T_S^`:+[f,$l11%$P/_\6d/mHaQc!L*908H#eL;q2OMB;ps4,:^>kVqC\p>%F`j0:]Q:?q>E\gYa_bYUSiMl1c;W_a*^QRaImNIG*@:Ssn5T.qk2(@V\<'%1E9>H8E/gp^&E7LjF@0GW.g29\U0pSW_99S\O@9\3PGjLK6liS&B..O%6GcF8q_mHb>2Qj#2!gF%NR'c_cT?CLEc*;^Oo9p)-L[jFP'`[0Uc=d51*,+`@=1Y066(!f,Dh6`52>t:i@sB;d*s?g`u9n;[)ZSHD4,A?D00X\EY$P.*-tLHC"W%59#a/.MOuKO::"^STTFX>G#eRsptm)&UZ5>IrJ$rRoD-(kDe=R'NLMUIHeY*Ja3<.U4s:p6N5$?=>i.rG+.Z4"ce7^@]CIRD0[AOOT?ZR9GlrD8[9^7)A4j!%gqA/*XA5GL^!H"Pr_sR:)2q6GRYeEt0^mn()uVmJauP2kO/I9`lW:\Ehmra</n=g*4*ge8_@k@/LN>CrOMG\30Tmj#ZfXeC>_>9#m7PaCkNUmh41q0>?0g9cWE\h-P7GZE#[&Fq*RkVF+g2bpl!7)aDX5=WdcJ(.\S7*XD`k>R1<kkT&S0Rk9U(cXb4]Z=U?.]T=%^5?5I@khAdJH_?fJ=$d=>Y$G#<n062&mf+n>Pm^;p*S".(4J>524!&;3SDc0BJ,A%S`R8>RM`V3H[_:8OoEZjCVJ3fMrNM;&c<?hS-BJPA`["Ma1FLc7Kqa7>k]GMk->N>(`GN&DeX14$[<RO2\D>T>4P-2G!'6f%V5:b>E)9\!YlXX:n2R7b\?fL1g0&s:#1kOKf4@?guujA$8I&uP'hr4-W\.2""LS4:9R48&%tE]-.Pg^p6hO.+^<EQ;l*,jq,>*RPEXAfX+q1&D*;m%2Nu9;S'ZcnMMaN/^D(4<Rq/fci41Qr8.TE)!"ooKd)cD%6XfCatM2C7cZEVYI757o*O6r8IT>5_R'&&C+tdKPip.0sI9Jkm8RFZHpU7"^u\YY`u-]%V&SGf01jVT-)gQ&$Wq>e8.me.)m!Irl8H*OF)Z(rR.C$o96C?5k6hcrY+[B%3"4Oa<#.mN5R&Oa/Iir0ODH)il"iH*^>DWjt7`kOCE[,k9p2_5NoD#([1)OX#i5bO--3DZ1C&$+h<T*mIS6$G8\U2+78^H_%I',NX.I*i,J-$%h*9IAfCsXbuWNOlu(bApeeLj<6B1Fh430Hf^67%DrkM*pLj?]]_h(\U/p.:jkC?VCu4ZYkDFD&^%ld;SJ(L#l-Ii'J%D4U:+;RH2UGq=@fI)pAIm^O;$^O&Hm1&W<Hbo3@%*f>R$eH$>^i^sNQCBk:Ybqif,4t*ks1>c2ib]PI1CVkW%=<]Q>qb"dG?H8/mk^*2[q&TNIJPjr/^AtQ]dpnpEcoIppfo[O^'Ebm`@`SJgqKGU3c:#%KBL2c1Ul-XM4f9+61O;4:Jn>Gs*3ULUb$Fs/>p(1%"pp`dIJ$SDWj1p^$`*nS^Y4.=9Xr^Ri@1?,M-u178Z0qN&fma4b/D+fA-?.7seU^H:Gk6@Q0_'J0mOOZtJa(q=+nCk34/@j=eSTQ4%hN3Nrj%LDT9$'Qqf_,OGb1fuJK<doD%]4Pnk3g*7sgU`gZerQa*Nk1j*I:)/c+#Dfmf3Ngf`:<-FPqMA?f+?2qC*\Wl#!a[CdlcPH1J8O9(,1MI"TM^(S,JjtoR%`,L7UV*K_b8rdX:N$p072HGO+^bj"Be-#Q5RiQ]mXNr;VgKe(aP4>in6Yn_9YDEht\c#r:JH(,!36BDbGC_NXTg)U)hUa[$L7LZIL)$Pj=ZVJChZ7Mq`MmHAT5>eYTfHO3BXij%ihI8n^dE$$1\lFMk&?cG7#>m'>%_Z*9,ELe6n^eW"dGKtV-9HS`"A7t6k^:N\,[e,K!^Y(_!rJ9tul*mDXnk)cd53(,S]kt$(7JY<Fo6Cc2g$n3MELV'D1[sVV3(bgm[kIBh5.0m_^>I>uiP*IPn;dj:T@qMRn+V"Ol^sj@0*&dL%c0-fo%EH?'jk$ONI=$SmJQk+rtI3WVE#.RnZ7cbWo'#`,KmO(@l)0G7+1^I]1(LNb<E+)oBr<5d<cd)o);s$Y,=FS^=lH7.ECYrZL<-cjaJ1'I]VsRB6VZnRIHUnHa.L7Y!4Z(r;HC`^<Ml<4/8VJd'QtZaEjGCerOd0rs@`tk]%0jPf6J0^0>e/Hk3]iT7:dAR-aXtJPcm`K\qaS+G8*oR`W3;eNB;R^bH"g3['$-e7s>)a"q7f]Z[THooM(jK?)=0<E`8U!qPB%=t*>K-ggfGS,;[Pri]DG3UJ!hB5p3J++s(CZL0Yj4hQ4r2L;!^c\JC?;q=.NIo\RW2LM^lr5O2R^Y@g-l%bnepS)Z/ie+`iq`YNdg;d!qYM"Efj5(lF54I(oLYrlAF?5EE7^L'Ea>P[.a"3-ZHo?8OUosCh+o-c>rZ>;:IatYF0^nMnK:_6(s*+'1np^PP:[\1IID6O\g:JD,6[\(95<%hQrj1YW1ES&ohkTk(%GYLFNd<ktVUjHSSf,cDPXIa3lT9uZM=!6Kh\#$)?]4Du5NoFUr+M^8e[TaI],gaUT19q]HOU&Y:,Xc:!d\QlT$<mrb^R<8Do1K*P!G"BR41ALof-jXUNq40S#bqk4RpQLro92-H?@IQYqeSbceKP91Kd&XOnEm4E?O+ZDOM<XPJtsSGjT?Ws*CAEI]J?NQZZ5D`Qc')ODt/]4o.(g*,IO>QCb*(D7d>r;6sXf)6[;d0#3Qo\j)NZs7Z/7rSQ5snm@]0HEdJ(CV-&oI($d#2>-)]nZT]9h&Ouqr%U"QqW2@Fgh@NS=RLd,ZZa5%d.6spJB***]_HoQmE<mND14g.^##k?Ie1t=b=fA)D2N_#k:lk&pjUfN?Sb`fc;/0Cph=XfA?Yna`D_fVoR?5:T[a2&[!$GP$bK[h20>rQ?#5h<rASXD%%ts<6,8ETKN=0?L7oFr%CX=e$%kML0d^Es).Ne986V\&N(ZK_8;7NK>(KA'X_j^\_@@na\/$cA3Y&qK@#H71"<iONpGDs9L;)7*)]3LbBVgS$\L"2`V,bm\JMdX7Ch::$.aWW.*i&A8ldm-3k%M(^A(K2j[Vj(t`9bVXPsGHP(==^9^#9@;OL,kt\*NsAT2[tObNmL<WVC)6+)X+6pfZ\(VMBrs><I\$rh"CIPJVQkq"hM(Jb?!7aH+*so]s9!o(D_N0,o?8Do]+))=N%OnX#_h1#pZhak>+s3G!?)m['19JU^Do8bD>K?f%"5CUIDb."mHpT;V>Srgu,6Mniq71c$1J56'*8_Rk.BLO/Cbk<?#5MIWbt>J:'a`cB`^<ub]R8E3:SmGg',=7ju<-1%)34h41q@HYttkBEEAorg$`0Al!f\+J/-^YSg:/,tXEo6(%Mn!5W#T+>1NolbD&Fo&9S-/J,N\#UU;]X7L9o.!Dl[fs)5*r!*l4RKrXD>&<;=<CE%8*KdjrH:J,p)n>V*=an^Q6ER6(';D8r#i1<[79OS=QISY/AWg_R5,JUJf)G%+CN!@UJOQ:C-WI]5R91o<Yj3u"u-nD@>08@llKb8C)/*t$F)ouPgLniT[mkXW2d5oBXYfGfa%e?EO=@Vd8D;j'Q'O5h@:aLnkqTn@?!#c%#Mn'!JqD>ZPsY]<5Cp-Lr.PT7UL$bfhGil+sTl[#ick+&mV85[cahVgND<*.D4uUSZ_0^+HD/P/jQ52JT[>fPD^iBFPK??1h/A^i).C[<R_l8)B]bN=@S+hItRnNQkT7EX5"enoeiup8;O?D(fDFL/UK]XOSdWL4C@>5r6!?pmA.KKs+f]^>nIoV"i@a%gqMJYQIprdh#-OgbUg"Y60f&+3fF1"+?;`<es?Y#1`rqfK-)lD5ac:26,S"!'<X]\(pfYSPA`Sr:Mo!-/>)Z^p;jU-&Wc,([T?gVdsulIoIi8OfsP__e36i:'?Bq8+0(K[O`>Yt+=%^A\9'AT*9o.,E<[]o/L8$<\iR=ZB4$Zhi@j'nbM@8\@)WTPlE]*CrI)BQ1@I$9^WBX1B7Bm5m[r"#9pFgmZUqcq!;7bX-lRnIdNhPc%#bniKO@Y*aDX:5ZA1o))$H"'Z]O6\dp1]:6V4Nggp&CM:cH)Y3FM(S&5*'u&ck=X9P5XR=@%ma![9*MQB>^B+poLsK\.JC[tHbu+.`:bDL`][h(/n`5%/kk*5I\\/m_JA.FbQ+fsTO?-XE%sLH$9U:("`[g6jJD6.uX^mWGIt7"M]cN!<rBfHDdGGr3@^JMHSiHp<<(/+3#(7eJS#6Hh.BQ2I7ImpogHcFGOW0fO=m[):VTb=\0$m3'*?ZTiu)^#8aq?0/YleZQ>LTmd[=Kfs5]nnF9Zi0$YWP"Bghnf-2@l(*4u%NDCE_]sl-#9lL\WJ`%D@\k-Vcq1!TDOaAm^Dq0am?Gnk)oiXA;_HZFd>B^#&1[u+(aKnPdaqoDQWg5UEMN!pHOToBf3E4Fm9i/nI80\!fE)*i9["o$K;GD3NZj@'DDEuqP]"piql-Mp5lK1+,N<.-_$o*J7OXXo$q:T*e8M\-S03C`O>i%N%$f&&cV)I(jJ>aK1;2:SCi"c772uL98ZRII;b;s&rk'AYkf&^dE24Um#cfEnCkRcW4P)Z$:DARZH(2\@NhLMD1Ee6c%(;Zc-ZG&<]K(jhV4bj%@@.mJJJqt1ds+TE,U8'nK,#;J:o=Cq:lVs%!h\/.ZrTl</jY>-S9>@MgGUIK/":*3PDm)C7#lQ/XHY5_)_`Lni_@?3N$:`^9^'l^UsKE#WiuoSL7E6cKqU9.9T)_&,Bk%>CLgYD1m1FF"uMknNB!(nNW<'GfcoLUXS?i=8MG"<NN"6O&[IKE*+T+kEA6QA!7SgKTJ<@d+c@"gKJGf@kWZXqJ=l!%+7;YXqeq+"l*K]<q0u?Bs5AZBIl:N+ZhM6$lM]-,IEh7:+8'[bq8p>]>;tjc_^/(>mWYSJ1"\_#HKnZN-^S:Tp5VjZ\q6"1%ZJt$>M=9rnVqRFLW_&Y@4'#/P!ufP(O),0"uLtH5<;#PF__l)m9nJJ`28pe;B\@8%>9NQ%`u1&KoLoM6#40Ii'ehk,S8APNj1?2Q)6!E;H^]5MJ?u[V\@Zu`6$N0:E^E",q2/Jm_XIi)uj&:K?mrT0u!B/inSBk_\+PO><XVr*-pP8Zek>ISdT+b$q_-DR6tB8E=RNC)Ua[PBaUU-OQ9Tq<+*/])pAPdh(<%"+'+6]4[4_XBfNnf%;0=g!Le>S'a'@f@r;Zjm*RX,mZ</5:A6;Q7,u3jR(QYU<)\$&+d$9N+UJ:9<',4]e%!iDW4Q](qD)Ccc/io>/VP)aLae36j+jae5)=Qk7Zq%/&4MgO:uZeWrgd%H;HY9*j&FMo3AkajkD=d7%[LN"%bhp^5ut1EeB>KP\_Djk,&kcEnN3.Q`hX@JOs%A.6^J:EPE,+6m1!#<5n.la>'*.u&P=:.o#<Rf]U-&nBno.K3SpJY\QhVhld>[Unp8%HM1KeBY;Xtr5jVAHl#NuL4+f+)X`iKL@9JHZRF>*Ib&aB6U6"c@rp"G=8s:XMbNPY<57`pIk_R?%r!rYtZ:XIJiIdum0+YpR$_fL_fkuSkQ>99,;n$H-<T9`(F<f[.n\X-0Je"rb,r_:-5AeZ(rWc0L3i_mpPnWE=S__ckea'k1-?IQ"MX$^%EP&pQg%[[RfuK-eGM8s"`-'(N.^drB4cDNPnZ9q&e%TiiZH.it8;J'bE2B`QCY:X;ET:=TmM^-3GgS=<"a+9m\/h$-[\Ha?QEB!t1r6<G;V(tY"0Li&]TDUonfsO(,-((eRu]/(*oDe5W`.LNLY<EE#;qdHa2<KP]:"VR_)Cs]/XLGkCLbDQRMn5_[LCI2OpeZEjRHd$YuZ?E/J(RGV:ZtpbA_d0f/3JHnkfm_PQE*X8A7rL`Q6s]g,o]o!rq7?"Ker**p3tfFB7kKHLCHs4W]!=X[q6]d20UhgkEHVB+50H-E"fn,q+RkNM,>'5BQ[aBp$#>'k!5qPu.CZ]]OuIVB<m"ZO!R)j(>[r9l<hr'PZ81%+tEP/h$]22Ci2&H=GFogW%S'l#+sCW&obUZS<^=rY[,j^#St7b:-j0GWo%6Hi9bq(tNgbn%([0[+N3q7*@95[/9!i62gf0F+Dpc0TVphR,rO8[T$s!NMFN`2hN1co<r[UoRLJ,0fBXee(AJS#/HMY[)nZUY^MMG8X_LK'W*0^3-suD;EEAb?oed&s2n(#g2r@+7QuWVs%6V[V4?59:])Ka>r0p#G;F<3S:ZQRLG!SR"0EbZ<hg]rF6"&34+f+#^!T.WH,_,dc<h\qpMt!qgi]SGYUJSP_)Fd/6ROHRKK<X?aK'Bu!D6s]a!>i]O_psiB)d$bZa#0'-Wo1W"\%3M+UOm'3QQuJA5=6>eu+;4qVg[EXU7IBGMW/!>;1_MpPA]*YeeP;92oXf@m$c#oL@MNZY14Q/Ot!NDn*gG9,#rMg!"R)m$hXn`g]i#SARfil/f(O1lZ&/+WOe:=BWC0B-t&R9u'FeZ,W`nK^?5=eOi'lC#kb=?V^9,6QPiXQY&]c7;V5XSGig?Q4]fBD0%/^Ud]qN&$%-Lp,1NC&!&%"Vd8Otkh';j-_^WJh"qh[R&BJ'X'[$YHBVsC\uaC7]nY0u@e^A)_[Fo3<=0eWU-Lu8Ebg2M-As%<9ZP_X\DTAECCP@2_RT62X*'<L3MEoYeZ!.p.*it@.hU%On&/g9E=ql!mk?lZHhuAj'.rV5MgI6^-+I<#RaUmTa01V.^s+pacqr[2]>(0#q*(k:Eu4%(427lo(B7gG+[[?[CMpJ2;Cl4ipJG!*fQ$(Wqm-iUqd@jm(/F%jjqg-T)%j"N9!p3Nh7e@D+6D$ul1T%h/DXO(-R7\4@6JTLoAb`Y.JhT1DMm[jEIr['nn2`_47K%iIVpqaK&+sOi2<WW[5!AB]/eW_K176l%>FRY(87QjZ7T+k3KN[1)7;235*SJ;g*;RYA]7\e_)G9sc"ft0q=<*;bur^q%QsMJ:e%,%iq3cQB,?`GM;,KLpoUZu8bHd6caRLACUG\[h1TRe$X8VZ:h6%H!cPOf?:#WH0/PL?e$-h2f(%ER5i6+uCkJPQrC3?r1k$9=dQV6E-kF="d(og$BfDe40RV.g$s\)ii3CC:1#X$/VSaf9R<fjTMRQJ3n)59#CgAe+]54m<B#Q$[AlrSr`Gre),lF>X1,j%?H$$>O,4P2)>#A8*m-BiqCq&1^D7Hb:i^cokL*C'QVHf<1YBG$B"O9\9-C*9N$4:map3p*AAO>KMFmnO2gc""/<O7hA7mW:!<<:J=b+2t5F,iW8ld;S'_R>q=2Ef04\j^;\Hn&eXUlRn:8CC@Z4R8VWX.`t>nA^JPGZ'8M<ZlRIZX9>8i^noL0+MD:k_CD@577d/a42>(I.UdH)CnIQ^_#b-E,b1KLC*ZQZ`Yb8H-RL\(uqq8/,O_^BfsUr=1L=Y,!D+0SS95EWE/e0.j@i\:3og`W]-lM2Vjp!cIZ]`^QRetegk:'a_#p<SV47kdS=UQ!T/i69\6<Q2c@3ZD:0-DHh:2eb*_+WIcG>V2H;AQf\*@IHmnkH[g<skWCnqj/[IhaEHMAPX1r6-npN(<.G74:]?0R8;DqDK:e?g56f":G(tX2"U6j)nJuL&uGp61`3o;S9erSF&^>(V,[-9!kmSL9=P4U>QZK8uOr,8+1[sVra"--4DY3<!r+jR/q41S)r;q?-:UD_%hT6-JbI,M9:dl=QhkkLj9W;e=bc[F[h.pLM,qq$.d>:MO@I<Kk2[*%3)$(#hg%SISR4HYN-DZcj2l&tTS[Ane:k;o(f`>Ml!<Q3eA;Wk<&^F@>$he/^LB1Bau>B*3r:L4mR=o?Tt@jT?CMYQ'S663\Cc7k$C1@iq8-aut3Z'bmU>3iOE'CaF,j>f@!i%0uVAX;=rZ_G/rWp:^XXuRB[-#UqK,V*(\1/ZA%2do@b>7"JFnsq0"=.K\VQ'K)]%Cf,qV7,L.FG/hbF05Dja\?AJWO+IL/aG%WHm<aW,4VgHKW[`&P'Mj<RXKGQ\scd:S[\6`<jT1ILka?)EfsHl2dG=3iUH9tknIaSfbu`uh5W$3X+JKLm4s$Vg%`mF4M9DVk37'X4g]93"_mqL"jX/*;Uc<LVYJ2c6TO[cCJ<i9lE9HU]Xg8mMe@XqM%lB;S<gaV0uTZL4r2nimJ)lBZM6:[>k[Q6XE:VfZ)1W>Ho0_!AZf*34je"$b&^,s\Jssb1t5Q+XLUYKCTtasrc^]"S&>lI/@pEo:Vq6ER*OSFc/C.N:\h[upK8j=jROq5ItPJ-WfK%)HlO=.WV5sO+(0m4IoIiR,_eD330[o7\GGlfmeE91ImmGqNRR@JT3cHKjj,4^@OeQUapXAQ(oF+_"uXfP1o?Wk-lQ<5K3t_N<Hbm+[qRhT!Q:F%PB'N$GqJFf$-IG62]\3N2War;+C@e?Mc;HMG_bI1Dt(5HNp[t`o%WHfRs<u6&t<0AFq4IuE['<.\j;Tr>O8f,_2E*m*pN.![s9dQZ``HQ[cSS'0)chmc\9u0Z,<eD6Z.+j2FY7%+DXt-fd<t?j`",$(.53(FtGP`m&'Zl,J)XWD)$fCT#k)2erjdmf0tpUMYl$ch(;gtpt#7N;Wo[KGpuj"IFVH=poS#uK!og2N2;9dMtYlFeBN3er,Otc7l7jH6HsM*iI2QdpgNc^qJJ&m3'fDdA*MYuM3r8h0UD@[6mBo85q:c?LD8(]&+$Y,Uq1e(btF0H0CZHB+6V5N^e'pOg?]'WZYc\]2rT($]FtjfSAVOgj;k#3*GKGV[>0WEoI4KgPiju2,7e#Sn<MWo>G"c)[>pdL]4RE"^#a5K&s^pjM*+r(SnaL9e[oh.gV2INZd18:39)GZ;Y!`lh6XAZ6?J]>Jp=XRH_8Ip=^[\<HLAe,E@aQr\RBTsO8<[,,D&r[$N!C^oBh"12F"l3YV1s/i<Kun+E6Io:AVE+B9&72/<SeE2WYgO,[!Glk2tAo]W=G5I?C+Z^)K^Fme:'V;W]Vl:VuJ*/\bK*0G]X!6MJ92,X0NNDS8$INPiN]cQ"qmgRD(]GIQC.Jc^B;m(R'D=5aj-H(h*41:@Qo6QArZS\D_64jrFCM;Mo`4mlS^4RcUbn=7$i3Hi+NktUq[>%+hZFGI#F3?.VNDYnC5:MoiD@];to&C'!(N)lD['[&NBPJ5<t3F:[QM[7!0^=u:l2+Oo_'SkW4\mDA([N4#o(uLHg5#R:P*!iri;VpR#D8RhLOt7!<pK^n$lDHU&U?er(9h0\ogAS3HqL$o7kJsEAEq%ks/+]l_WZ:HnBsdLMpjNjrAOg&Dh@qdg-\B[c<_j[gF(BNhIBGN4kAqGrkHVidG2md6bSM3Qqa3?'A%Lelp#NU[e'Ue2XKQIpK>i]1(+&B0qeqLTfXB),m#]qGC=G69oB3`t.a-T6K+`Y+ALSI:n<D&aM98rr,0<W8G'%:.$:.U]M:6\@HE%)OqH.dLN;[:^ISn=bqI_M%6jZ?\he]2(Rp<<?adT+i/TH.HXR#QNPeRlu\bO+F]URC!&2=9P3IMnT*)Pbj#-QMrpUTFa)0AVLWcOZjam$q,(;l?QMq7Z9Q:H>R>8@-[K3N+OCO:*Kl,Y-+M2ml8GKbb/<BK1fi1G6[S@h;F.U<3kWI18Cl"i:Y*m.PWb:q+ofAC^Qo``oU5HS:RG[o'JV13QX/\0kK6s9:94mOeJooV*$gn82b<jZn])nke,loZ#1p#\3'-sQ0E$,=j^B\`Mn-rY]*lM/qQW[OlDfFjJMZ/&FdjF^50`h+$RmcC&MD_b<d>%S:2@tCh\r2lWT^>uaTh&gg-e7lGs4?";=5?BY)Sf@<saj54T\/sHe/1eW/6G&q*@n_uB*>jH]G!"@=do,o&lJ(O*>Ka((C!LTCRjW"FaKj32IL%jj[DNVE1TN&M&.WAo`(\!$I4Omen"Fm;ODR78c1(H?Cj$`J=TTaBG:7=@/uk7>PH.7>-VZCVLhMo!co]H)Mrn*s0;g0B?-]TOk,6R2=??i:9Tq]=*6uc57YKDCM:9Th4Wq!OB,m]lPjWth9*s";QnH"gfC&:!T-LN`m`C6ugOr=Z^P?G6(rprR!_o[&IL8@t_Q/W=+u_R"O:W]hZ&^=f.0Ul]0hTUrBr-RM(t'JKhC_LBU=W\Ok3UVe"ReEO)akNkhH5$KQNq^0ZqjDnrcFf7E1GZ1M7q?g(q_#j6SjRbQi$>k>Htf$*0XJM@I"p2.f)=D@"]dcc+2F$R\clJ';R+$pE:>O3cWVq52uH-5eSu6`g`4D5<i6sAg=Dr8##._<Mjp,Th,'q**ih69SS55M<11<@UOQ^0cg2!pCFokPNoFW@Dfg'3(%pF&7dL'e#B%;R\87E/4R\UcTL=#KrVEjdEra)=jN*jDn@9!8P]]b_<1F@\)fd*e$lA-nC^HN&\ecT.Br(9NO@HNY7FT?F2b\LB'NO:Ee:Af+[u.)&*Pg+3A1O_.-rs)?u:283b$][`i9M1Ji`=n'XWE=p^]h1)Pe\($@t=Q7mOdj%BIu5OQ3',GWr6^QXTfdfZ*_(i;X!Ap8Q9aE\D6LaL"%flOpSm:J8;f^rZ3E+7C0uYO*aC&t/If$$p\(&*jaE1BKId-)*WNA'!iZN+d>4F,&F(S5?5Z4:Tmq#XGN$A8RF+M3]ZRd]Eo9,Q=c!6XCi!ApFT9Tqr"H_YX"q?gmf%GiBCnA%DMXgcll)g^r5eLjhmPl+J&pOIO\5H1)]q"R-4>"R5;42;7o?#Z:V[bl28eJqF=2"*Y2@K3t*ghT3Ht=1EJ+gtN1\VC9f*68*YE:I=&WY6#"O]HGST1,_kTTKR<8$\ijCp(5c3+/4IU;tRj5L:B`VA0MNO5+/D)C9kW,))DBlSf&)k&BD$j#K>==MhKth]DYP7gH[`Ij@-?H22H:R-PN&]o%PA?K9HU<CAdF?PkcuoYV#\M+0W+?%-]*[\E\fY&X/ll&U(+Og04+b>Pu(dH2jo%bNDEnE;.T9#BUW07o[^WQS4;J6JFU4b0P)elJPZ@)*fpaGbjTQMZ>p2d!6='Kqmoe91RICSV+KSQb/=+dI=Tcm($e?P"0HPZ:%9%l?IBigsJTCdRE_I,l#d>XcDu?LpbLZ"7TA7h88MRF(Th?cF$-sAhiBT#>uW/"r`P2@MbqD/nN?gQ-man+e*)uBZ6pB?H6bPek;3eYngUqApWsr\Cnhbk^D<paV'<k>ThQ&84-Lk1IhnZ?&qC:831CKO.ptF=N6Y#i?39!cFpR9Tuo,6]#\bq5M`,:MQnrSDB-2bTV24_r,$QYGU@0](sf!&&C8p9SN`*pb\]@$:E*!MY7M!F=*YdHnG^%1=T)(\+(bHB_F7(+C\XdU<E(D:`gTN-C<b5AZ]Q*QGg*_16sB&ilBtTH[%Y[_hDT61D>Kc*EagoBLD]WVp0Dk#aeWei;a*Zja=Q?T;LU9HfXe3RcL>NhrFnI]p_O,/(BKI1%O=*D1M'Nq3.olF)-IAB@A:Mc%2KB#11LT&6:nC$E(c$)H$EUF0'h>o1J\OoHtR?>$j%dQil#/,>k;l1Or0b(3tX#g$lOh\.TX-#!foKH/8cFT.9KmdDXkQ%,ka<]k2X370&ki":t&6g9?L>:#R&;&4@?to+Gb2o`XTY+)_J4[I\2W)o2Z.'VX/j#L]i]]kF)P0J]^LK:0>*6@iKu+@#['&`_ND=dSHJ5/gS*iNb!%jdAAiZAn^")V&7eJbt['eT;KdG>8!hLY]2gi9[U=m6s\J3@k3.S5l9?ZerY"7,/`.U[6B6aZm+Dlk"q:aL`1ImH=JjsB5b*/[3[G4!_o2R1DsGYe5"_[l'+PX?@B6/GfD1a):<mG@:EEj/nE//6FCX1Y`#[$q*j?]QVZ<JL>Spo(CEitA33u:J?mcfjip.a(/oa-hCZWUQ9'td,SuZf[)HCn/O(FH5\lQ@25][GrNDBR*'+rm3*Qh#q2r%aCYr,A^2&bs?u9Fr*(1)O=r<t3E9@.c(50Q2S3(f4)X#o#Id`iMNk=RZTa'3)ZQol_&q&KRA[B.pnk28I%lCHXS'daD*8k>7A>+kHjOQ0W%Kis&]l$D]LB/E.;93q@%rJb:dQFaH0;[(29-fD9pJi)+#3[-M4:O;c6:XC6"d586\F*uNs)ZN3gRiCJNJ1+i\#JX"$.]T`HgpJB6XG*nOOf,aVl(J.RaEino59`T;Z9iSk!c?r;aQ3CHP'R2UWb(7JWhk<(n.\R1Goe>6s23C8M_q<$9kWF)iD[tOt:FGF]5aN`k:'2-Rk3UF)D+0n;-b+OBkS.K,`79jqGoiE]G`Ap]i+7*R:&)]Sh'jFU!)FFV7[o`NcXZp5\IA8(jFghSPB'kmS0?jc8\r;T*`LENg7&(UPpjXsd]B@D%/_3KS7Pbj*@WK0q.G@@as&GuRbddadBXAiF6mUEh`8@s-rmF.jS_]9:O^A]-oZq;!>-cfd98@m"[]H/trSkl+)SQkB7'Zb"_ZW4<DRR1s2W;Mn0k6Fj7hgn!9;3fuULl/R3lDcbj_rug@tm=4Ju5L#ogY:hifHq$AneWL-o[n(kK*S0;Xj:P2L-@gUqIIK.$H3<lVg`h=L:)`g1lL,.d\F@$p@c0Q*r'#BWm;Ge6il<bi>?db9@65SWj7pb64PlHURN'tGIbF>YOn6_DD.?bKj(ZNtirS;1+iQ7?P+h^)!&g3&f=dBQmfI]=&s%ibn<>cl0]+T2n%_QTP_NZY,E,6g=36_h9\[V4'JC1NF,ePrJo,-aKXR4WrO]Ni")m:TlZ:CQ9?D`_2L2a@SI8n,Ua2pX\.9\/S8HrpRGXK;c3)2Fl.eHef$`(]9"OP#c&J)-N:E\r^+N;ne%`9;mr^<Ybb6rA)N&mb[VC^n,O>HH37skD4$eV71#aC>nD8UP-G[HPWJl9KA/#[uACqk%*R?V4["t3nfcZN_?SE!7Wq/ud\UT.%#hV>tH?KQ3g+:dm*a2I"6STi3Y&.);A@tflnk=V*1@aCQGT$\VQQsqdKp*dhNfePh.Nd%k!otJVJd_:m;f6s3;,&jU(3[f[7X!d.#-O)N'i>cpG%g6h<^d.6`^L`rgrRRXpXc5Rea)#L^4)f2@[M9N*$I30c*^JB;'1b>)5S$Eo'9p/<eH>LWo9OHG7TFB,Z(7takb56F]T>'(S""rJKDXW^[0gR!FaCk<.p%:>7J]2Or0i?Bha64/gFaPj;kfcb2n]'r/V>ZKk!.Oc[(<%083SVON'dP+a&E)I%$(?"s-X`+q5E1YrM/5ZoM"AG%6oL1Sif27AB0o(Q$FH=,>%gRtKUkq1Pr!"6Moj`!:i9mrb?mk!:"XF&S3gQcOjR6W[1t%H+#fML%U"LCk-@d<Vq.4j1$=GK3qcSJS72=a,tGEsoM?6Y#c0mie+3U#cjl'L5'W9)ucQlEj;m*Lb@?!)9+!#fJ%E5X.d*k0_ED`@0"&WjbbH4\XZ@q=Wq`UU3Te"mIB,'#QX`-QHp(8sN=%iM/j;H$@@WK8e%1,\!++1C?Lo0G/%\%o#ulG\Gq/IQrlnSt0MpOg2-pS`h)AZURG!)%5iM0o_n&7(LblaUntkX2HhqPmm.47T)8E4QsOf3d5(-B]7:9@EJ$)!a:49clViDG=`8g9ZLpXCDdA%_]HMr7F^T;lX\4mLkC^(=Mg>H?[Smbc5sYmlt%&eDnS$1\u'9e0'0Kr#Hk_#*^*[IPfYaI5>G\[S#3Os,%H3:S$<B\D3^U@PT+2FYX$6WSTinL!uJC"DUTt[#IMOKlpkai@VekP0S(-V-HQd7[<gLu8-D=ipPc1)*!/ZcdYXhR(P)DQ:>T1'p82?p;B7@HIYg4$,R\dF^7\f5d!#_K5^#KtL3*_p];G>76Daj[B5MbVdi1(@Q%IRC2sqkE,`F07=W*d,fqm)aU%F[je0et*'(&>=;Wh,)h^^T1JZqgW#*g7e-DSWcB)4bP_F2jmPE,I(5@.bT7+,q'Qe/,Be9u?s*FP:s\S`AgRh]n]V_lNIB`cY&3J-&X*X>7jk0]f9nX#HEBn4*2'F':+<>,Bi"lgq2e'p5i#]b]li7O?9bLE+(XqFV+YD1Yq,(a[#2g"u1Bu)c(1Sbp3HP1:LNN(-AOIC:LHO0tB3Q]4:j>RM^?j@k_H,i!97M-t4)ogKDH!]Ppfs.#nWn6]o6p_+"5jsS6Y(_ZW:MJup_\mfpN@&/(j@9mS79<Mb+I((TOU&i^_alo2CiuB\?7*d&lMs)]T%UgbH4U2*-]BS%+HF@O_:O6]G]X`Y^+p33H+r(.JFeJd\8H4KcHVf)k=D-P`J@%j9>OK$l51s*^?tA/!H<T)%V1AE/abUnk7#RKQ:\EE#"F!:(^!kZ34km60[m77bet<9iKC@80s^0el1q6dWjRt+rDpj@3:^@W18WR^*A`R`orLclhgFq-2RcPodW]d[YeUk6B&I$LSaMhW\EOaZn;2PB1ps5&1._TrBH>EhHs(HnS[4"(=i.NpL9V[6Tq(d]Rg=2Q1fJdrgEo#_^AD]d.AgFZ<C]ZV_HPNsbeaD"N<9Q8[40l;I#YQ]+@qYiU@#KnKJkcdY/:*.07L:D)8QD8EDd$Yp+3d9!EX]<dTY$s\"8anGKEJCeaegnj;!J]mNVf7r#Q=RYXa,2rc9i<NcWA2I'Ct]B$A,(0r3^+Ce8A$kp<fQ-KJgSgh/%iCH)aMLN&WUjTZ9o.4@nb6GjoW.QM;)?o9aeVK@MPdX."=3On^6f"r;m:j8fY$u=Fm\9^NWJ5X7_$_<=_MAcXBG>C.S87!,Q';?J"0-ojG(D5U=`on`Zi9oJHG#!IVLLEK:Tq14fV?G'V0j]o/',3`%g.2DZKJ)/:H/6T&"7Ja"a??pXCmR[$?m+FbSf79BB4l&N--jRN/09sG"K2m7o0WXl5r^,O-pZl@4>c-j=>gf^4g<aTlHH/0`t"2<1cIFNEJL=EXn;L"@$ittF=*`$4(?]B!ZShfa`+m`G#:j:+r$[$fDKNrqrmtsSfGQg\PDlE[N?meCQmf=Gt$"9W([U:pmAkPFEk7Bh\LFo5$'eA@!-YBVNm?J;Z@,;"K96uG6u.X!SBQ@iALmY_r9_HIM*n+c,81uVoAY@!5-)hgEG:oNRA9C@&4;;lU*Vn&A`Z1UlW/>ENd7d#H!,g<NQ!gOBc&J<pa8)(E>>X^/pT1UE6as<&ur%9t<+)G9%t]3Tl?o]4XV>8i.R-qAi1_!+r@!\.HFahrk"$qL<_MrnjuIqlB\dV3*AdYO[StF8i"><^.,`db7aT;6K8&rH_[sS8J6_"TQ7=`?0I=?I$=imHuRnrk*bgD9"[g%T.7sKr)R$+jO^%r7C2YIcq^bl]Ra^jFIlh)F-fhYIj0l9r&/FGK+XDJjB;lT8cZ`D-"6QNjJ8n45"pPm[?Pc7[4UKcjP(c*P(LKF5GWB8#l`--+h(WL'*YA&:^#7D%Wt\GNF*TY<Q`Diu7O$("+_h""HoBe=Dei"Wsd8lIYfSce:nVpNCLl'"@F!br[(R&HCYVqkf#&"DR?4f.;\VQDV]l/M\P_%[6UT5K:qccg'2WRL,0X0>"O-j78fqN9gH`n7:20*K_NT*/Hk=oK$ZH`8$WKSJeE5KM6:$)XA2(g+o?$?eaft^516/'L"L)*iHnYiJqO<.7&"sTaubiRZf\\CA[F9_82ZD9QZ#ibt2S`'YDDRi]nB^fa!0<h:Ljt7VEK3SRAk?k5,]O@j*I@5*(W/Q^X2/[*Y\,4JLB.<g)f"h^O^U":T5n+6$$kqS"#b4oW0#H#SU<@u2ub0Tm.!PamVJg+8l[d;Rj!9R\)Knls8k9;%DNHG"#O)./"!+hAd7s#r+B?JljG->3Ds+.iQEO5u!<oD8"s)S*5FX=%@8+aT[0*48@en=5D*eXnecl._J[EXn)d[uo.$c[VkMeW'R:rK1m>^T'GOr+@PM]D)h]l0<JCms,UFh0h/M\UqTF-A[&HkTXY4R&W<aH\\f@ce\ER@D@$$m:LdmM3arZqUhFQrW\G]D5ApL.&d&Wr@F6nrZr`KFXJF>kss4%rNS5ppjjgbPcJ<j_sVOAHTNh@gZS#foC@OQMGlqphD&rU*5GmY4MN/ZqRW3l;fB+jHX/DRlCAmC]4SZ"C6@e4pi)__SEa.[5)3M2IJeH6Ih'>f*29Xej218BIhH,77E+kiCbb[R3/tD"NA/<m>&`o-.6j\#hbZP1Su8d$:IOaBO3c*E:6dp3)X96s1]d+BrMW%r"(]33]qCk@l:o%RWUFc?DTq>o%h^]a1MeFAhdmuToH0!Pr#b.dm!'k!`9LOFd<kcD<@/2YeXQ*6Y?Vk"rGa)2Z>WDRUgBc.Gtqip[G^ahL<XJ=jmBUKdd&LE9>3EiKP4A_N"OO6FU3a5jYP9<*60$tite_-P0H>=[RFagq@(J6]/TE!0Mh/Mk'+"ZAb#iGL6k^(L3&@88TY/997@2=L(giJ%fJ\TqkBqS_i#EMS&`I;?s(D(/`!eQYSJPdBi(f/ZS:8Y*8?=h0:V'$SfT/0QU@LoW`;8?o!MZoSUIraKJN_m[2pcI]2d'+ZM;W>'C>gB)TI0k<4:LTEtm7o98/(Fn^BU$S2TPQbEnm%MjIPp&Z(Y#1Bg!%\RM:@J5kI[7$>>AB@/L<9b"ou0M].Dm%$oGbtC.k-_o%b34+00gZN.VnZmU3OHQpk?BAr>Xi*Z6bEqfB5OmspB=;A8&os`Z>"ps>Y_aEj@%b8"SKufgf,Dsi!GC\@+iIuJbn'M@[_2?ni:&K^-?SV[4c'#nFIKRX0[e6V$A8+lN6]AUC;@:TMB-PGGVKIN-Zo5hH*#F6Smr(\Z<:kec<Xuk=7O5/3GbF&[@I\iFFNZ=8k[6XZ/+qlid5!0pX<NZe9dKb]73ASV!cK=,)4$/%rIVrfV$]]n`,]!jC6MrT_X'Bg=Nh)lc!tQ8bD8T]A_U@JEo2XD'A,/;"PB'M$YT$P$!RT4tp8RLe:OYl!(I&S[hp*j.QokIFOKZI=pd<3OBY>8r3kdDk3,XCYp/.V1u\j.R:X1E;X$(IqueRc7X@Ac6/<RB&lGB;p(0l--?hU4E2,b8'0W"-0RR]b&[3I;thDg`5f%(Jl-36ReE?cGpGlW#<*?dD4OA_OR22>_Y@jNCAW;5>-=l*[7X/pbA!)4V(i<AJUY%#;bH#r%l0N2P#!LPX%h")^BU5;qY3R;deE"FI>eK'3cB4*$4SM^/no48<r^:mUEIg$U0l,T+l1W?:D3*8Eoh/'5-@cXqX]+$^3ClCmSOt^m8TC,&``8DA"JISLt>ktoo%\Jc@`LWn[RQDF8/NbdL_3,LZ^KaTg]QUqOPeV(0lLt6c5gUCYs_ST/CaT^<Zl#Y9sI.ZKY5-gY9t.+I,Sd*q?aSmC-ar^,Xb-=.A"7>e:847^^t-ir%W?7r;/4OTH,DmR]#(dmVLqj/8GpB"RYQUr@MQLNN-,D0FGY/B$Y19>Z0>QtH"&*S%TjZ=@n?kr`9qN:VJOXG'E5>s[4^h!o]l/8SkJ`aZk%+4*o+1g=MQ$YZ\@f+K#2EiQ'OSVuZFcVf[U(unCTq-20/^"U&rA_)f7,.5FpiFFn@VJLobgc^LP<:Pq[,8iO/-AJboQ&&FrB0t<CJF(RP/>F'Y^^mC/):+1_>!bj/65\pC'm&P7+XR[inh)i21g?0@]OAS6mIoV3o-r+'f[,tDJi>-X&.N(]g@JJ*q&ls"^Qn:C+@Bgn`).;C88NSu(8Hj1lak.L8EUV;[&8UpSat1C[V`0;/i-2'#J1[CL6$I%F/Qa>cVr,bX:`f8$BQL="W<?pL()[_Gf1gG2Md-?.;4)fY1dqA%+$#j0)W9BPs+U@>@\UWC;'VZ5+"'f3a/P,cT?BghRR3+Gf>&<")*+FYm2]#[Lh6++T`c^ADV[.$RUNRgS$Ta#to8YK^r^bgcg]9*Lhl7"38gl&0,i5)Z2Vm3ZO-uNNir@*DYL8=7==AodK<\48X5eH%n8[f/7W%@ON'X\hYE9VQ4r?BiRA+3r'jNI_j4'o!E;D`gK2ih5/kpL::`C<iuos&]Z`"&iuG*Tc@!\4+m8!EeNiNo;a;1R"9_TH-sZZpRUZMb1E8mdQMC"DU,p(L*I:XWScE<\d+\B@[<]@(jC3cl%t:CkrErbG96_+WoKt'A$#!2dqacJ?HV@]R)L\k'XkbZ8+$VnY=cf`%m1q_2pkr9ZIFVoQd#ib9ThXa$&1c^qA&"219V@7(>SM*_;3r:i<>Acg$Gm],ikH,FnXkE/JM$Q2r0Fe"JWS,e&s)X_-'<(DMC%tORq?@l;*lPMB4\DZH%-7d&J'gmI;BPY.6$D$X5-n@n8TmD2#+<$:Dd!8OC^?2+Q[jHcmn.-sMK%IGLoeSk.L)3S``&<$A9[UiU#aUG3bs2;%gb2Y+D#olt<HoD-+MRu,2RrJ0nTiBN&WZ,:B\+hZh_rLPYqPRjA2I+h(o87LsA?KC*/q0BDo"i"C3Z+JB'H4J6k4(*.U#_sFG`uk.WW&qUTf^ZcOn290%VsK^*csF`t`--,Y^)_01of8.5e+@*V,fM_Dn%?/t36gF_=oGh@+D:9gI:j9WH_1&Xr-f07cblS`'.8-nl;"8M#.)Te#Pb?-5Nomm,8^'I&;DlMMu/B=1mt6:-JOe#8rEHs2!t%hqgA*_D&J0R5p0))2Z<HV+oPVQ4QNUZMtbq"R.6hdG/sjk=sf#lk+eb&Xs<i,J`;0(>3nGJU^ujX(6NaD4#u!KP5*PGG_(E)@??jh'-7K@0]]CW7jd<7P"H>?c3kVe71`>4%K=a1?AO"k*!1'tBnJJ`B8GE?1n!<o4!;Ba"1!TB'$Z0g:KtN0Yqn./%C[?)'(NJp"*$$8EJ\uY@RPq`@T/^LU9Ke)6)>MpQ6<T4EY(:.'NbJT6(l6N+W+r+0OX3@g5A>@6*sI>+rDKF!uP(=!S!i8CeBBkcn@C;h)qLaFT0(.9JI1G\W[KOEb=.`/rR1q]'^mch*D1d]peZ>j`c&qMome(:\ODtU)gHknNct4j-%*;%oNLm@U^00&$-+Q5WT\!J5Gto;5&6*3E6I!fnAqGokFMe(d"Wh/DrH^38gOZ*W0CYk^ksf['#!Y@3_1s#9ug#P:p9,HD?'T;lb^t(GZ_MKaNhp%[(aOK\Vj[3>dH%Zi=0`qaVt>#h^GaGLLO?ilABl@.)7$/&[5b">6Ud'3.6L;lE=[Nj<t%O,_^YHGSH)Fc[*[X_0(>)@R*A!Tl]q<2&+Meeb/L!D%(VM):D=*midWPrg6"M?8j<J21*[80-V`Z3H=kTh6X704nlSV?A?r"-%]^<-EorKQf>iBid*YUsu<-h$WNTVhCrZJ9$:HJsYHrG8#3]?-m*_OiFUc8l5Qt@EL&[YoH";7E0EWLk[C`9!J@a*\e>-8cU`/,K8P$nAPju2(I[;F,C\!/UA:sm5#6'g-uoBV_s;bfQI_h'q%J5[K:MnB'aG_U&7!)c.ipp;BP0bISq.LpR)(i%L;;B_p>jT)-9=SM>mt]q6ijkRLPm1g:lC8Aen(X!0QWVNY,SPR^cORZuk#Aq3jfg.at!fDA6d`FPb!2n/Scho=#(lW,F#%OWMS-#1VK32k7?bE(8SP)S/!b.2%AiFrblnoDS4Go6d1^kp,$_Rh!=u\Ej#RHo^Z$cGYr"lfA6nm^>'\Pu>_rHUh$-pcYbP:eLqT+U[VHN^Gm!-]];q5uCL:K`e\!(bl/QaemFG"s^nE$AZi)h(*S:4:PL-4k?gPFDKdV1FqGB9Jp7GjuF*"WqH#_mPrEAX_0$f*'URKaGCkAF=N&;3tRL8#QtDF>f_J4PE8Ah`55(hCZ7OhT>.Q[0_EjBcVrTS_Jkhc;Ul]YfOr"BKuH9RI'p8?/@2p6IJ(c%f!/YpffZRcD/qokjS=sApVjS*jNu%%_^^]CjC+HI,f74"dd7Bu\W'c+Sc,&7GFb$j=?N[/PoD.g_!4;FT,*QZ^M5o&1;Oi[J,,FNj;2dqDKZu;J9GL;M`CLoIm]NBPR[Plp!/"`Xj+J(RIR*bA"KE'ZHctl<8%UN[pr::S.`osZ/'&qoCJ<mb'omsfX5Y^p]LNAn3<^TpEojrk+nE7oWWfF?eD"+rl%94piX,&+qni+!eZbtK2W&2qDa(-0;oEWdV?%0$?H0=I_d?3(:*sC@Cuo4$p>%%$^FK;FOEq4gd[C#RK#fC%960@[m[L3m7q'%PM=R@W:U$E'SHB-rjW^A'T,]9I\5]1,a(Y&,e]>k,VK*/,_(ilr!`q,#Qq"ilDC+b(8.<Da(PDFTDHFjK#4/^AO=MH0fStE>Sf[:hQKfU0`CNcjl2NL`=2`bo``t#LPVYAc7OrmQ.j5;3g7tsH(Klog5?N(5l[QjcrIUbTM2TQ`36&TaZ/m?dR(j3S^1I!@]cno/0GF]6kZ:*#]u7;%amc?3`O!@i57>ZD3aZkT+]XURf.kJk+j)lX9F4rTWKM*SpWC(.TT=CJP2%%;8rnEWUT;"7`Sdn*D08/8ul&)jR!uJBFDIfRY64'NX`et^)E+!Q42/o66R)<"%*t:_GKI\'+BdD#LImP.FEg/rXpJ&\n!WQ[c'0VdrW-V@ijW(j=+%+#Y=iSSpnhXJa\m[hV$d"h$UP\e3ZG1FOJnEM/A2Z,%GhGR5VX^@+_r`EWTL0JDI(C7c<K-Xf*=:lDPtak98])I,KHDW)779e,u-==6fK>jEuL?:tVunnEqp17/]mV![9/01MjprW2R'@Pgj_[U$/XuXl&GL.:h/pY/u6?fKMbo!jSGBgBVT;2B[Dp`+T51(k[O>!Ro3q9#j:Dqb46s1"ERQ%2o,*BsEm^;L!b]GhGbmcld4!Q_KAn76jf%rgeNbZb5r:I8AuKEgF`T1:$j+bDdI%B;7!%Zml<WkO%gg'2Q?/&%b0clj9)g\SGtb<&J'4lqCu'F5fg!YG<1YNI]Gh!=b<$QCkk)Ilbjh8AZ?sd#1>Nii%noMInb3+sR7h07VH`]"MIt>n)OAY[,#R!;?@uqWCogNst#g?31[i6BU,>S9?OU'-tkIhgaJ?%"_fcX3'##]X(.sMZ^bL*7AWYUmji+%A"1WSalXQCdIfEhb__e:rb^!3(#1e6aT<,+Z+stEP^9jL'J:s%DdDJdna,]c0/VQA/]DOL;:>Y*&6/:h9XZ@`o`O/aOIGYA<,YPJBX5PP97,2/$$,uEmTSc6\J%W;?YX!R5#?P0m<1pepI_<Nt40_bSTpL%*m)7*l!8rStAft5rX_/:SMa#!f2R(P7j])8Q=D9<Ac(lAY`;T/?$99N1Z%&43@4Icq-G<Y(V)6N$BM-Tl;l@9?JC=UD\gpJtTGGT)(:-',cQV[#,E"[2>>>eOG1rZN:t!*2A2-39[AT-?[*R*0GQM(;FGRYLi<j-ts>smbPdKRI(SArJ/\:nDeB=))b+AFE2W"V(N=6B71=KW<bq]bT7%1-ppG2\1',uWiC'kj.<5SDo(GC`&]nhcA-;D&<>=cmB.C&iP1F>9Ilk3FEoBuG/q3.Zp().[/.Ug8/(_o,R>[q>r[Q^p_ek)l2@5@_=M&0kOCdAh>Z1l&'rRh-b&P[i;c_?IKZgKk6V5"^B5"-h5'eq_q=kF%<u^,j7X\[RHsX4!,t@pdKm%m<&fHL7/J7P0d>r<%g`2L5:@SqTq;S6f3cJcjTL[&aK+;be54eG:@AG$"6;o3G8\ZAK#P#\XG9X\&-4h>!cp`uA-a+G!Q"cM?%LoN/`"W1h+7pe5iTaB*lIPJ:QZ2$0LRerKq$^srbDS$4NiNMO,ent7/^R[LMg\;H[n">ijj%>VROnGL'].]AIC$Ip34LF^K]mVfAQ,&Yk@?EHAOun5n/hBbj[5m"\ukrW@6F$h^]h8jiU.?ia9.dGBS$D^`VStLds]1LBTa*6^FB>Nj^<3:!lEr!$Hb8^.7qT_K/*3o^%%IpT`0k^8*I/MVpUR-ZbS:a0184%t"H5$*T(M(a'@n%n*.F%8hV:qA_-\cfKbnc"l0l%#;lho$B%5nFPfO->pC7`s'[sePMB-7oFG@$ETTH7ak`UYs&eo[?KUQGe3r.ERmBc^JqqEE4qg5bg:N=G/VcTbeZ"SboW0:d?9Ze:'f-Warbm:`!5"U8-m(T_tX+p7C&EP\e8J^fQPoaAkNCM=(lR`LIK"#03%CR$A+]Y$V5ka%(-3]!CZoi7)ia],o%mHd:_*/Z*8$cnR=Y4lOs*G@*[ql7jKL[=(Xr$)"'@iDG,0]9;/sBVB,eHMX$6;?5]3>RUCKUVss]PpSms3OjCAkmC#?.&'W-Sj1duHV!=`Re(X"<8$<r-&ftZDf/B)%qc/\4#So9TN1nQRbub">0K@;I+H,#/+&Y@31s+gJgqr[uqL0(#^st":EALHo'9oe+8_fX]\7:Hni>)-@_3!ja8/B@(1t?*T+R5Q)mDK&raTDf>YV)@0g%s"SJOk9?5[E=_9mALk&3#8NnC1gm5&I[?N;9]:X=F?R$I`U>=QdE@1o)2mk57=PO#WBpP[F+)!k,@'VIOIMWkr&Lb>`',/:f6",PqFd=\pV@21;"On'f&KoH0@#q>DWCd=KLc(;IfHmQVrS*TDL!m3+k@#nfL^-bB5j,?%#on?KLH0k$KRGAlZd?dphiic+i_jD6"61#HFCc8AF3CmK:P'UB%8##XWI+Zi5s_UM1Oa6FTeDM-KaIp'J#BsQ=$kQo*=PDo;Gac-Z1arAs"cqqK@'`EXA\.nVT$o`8J+*P][!WnS[0].f#*MPU*5UeXlmUsma$FG"5VJ[fba*enr@>9_`*oQJ/go-sHUNsq\9jrT.OTe-]c0,":l1LZM@jg"F%UQrUOKV*&X`m=#!H"F"-hC4(\)PRA+6XlueCf!nDgBg2h3rP:gV0Ge/-J0CTOY"/85TqN9LTq0mer8pK<2$co).$,,[JG5n2pLYem`'^(FK[+s%WP]fBi?-rpT83ltRQj@OX5Br#-k*A=Zr`Kb.+V@Fg=&:^0DC*+h'\J:D5tj<6f&U/Zt?RAc#@eeEk6o`nr:?_Il:qKn/,U?qhCM8MjCq=f(("08d,Ih"@',$:EVp;%1*HeX+\aSES-=4f^]jl_S!ml\*90LI#-!/)m?N"Q?jN.=,hB^C&1pX.<J/f>Pajr'K4-mC2Z%7I->`'6LNIj:i4+X?ja+$ZEuA\f7Rq,lbQmlSF7=@NDJIKdn#_nmQFhWmJ3*1&4,d>T34G6A>@J/,Zs8!3^,4jBX56=IO@,E1WuaUhm#H]O;N]k0gn+-Ko+)`YVg#<(bhgYEue!@\$JnL*[`,@[c&S_DgE-Ie?WMe6_G;%=`N8^jK&mHhe`g8,*r2*)rAQGK$`W$&gufG]04^UA!*BORocpi=jeMopgb3<g2r9ho<T\0e/Z7)R)R=\pAuTuDCa_+s@&,Z8i0k5@;4PG^_$Ni)nFN>M:7-m^Jp.>4f4-/%:BC#ku/+E/VnU&_1s+Zi@_jLq,%o8\XYJbSR,T6]_m\'T#&c"u.q+:q&UhhD-giY)7ekHJI=NT,'#V$mJPKT]iUr;JuVqFBWuo$4r?.1T$F1et]&`[.#UR]m"3%4<,cg@FKf5NbJYm64sla=m68"m9:?Cp)/]cU6i9]g;>h0KeChXrf:fm<iFbS``c3672Vs6s,7f9a)WCLG1/GIe1B\HY`l3&js%F#@Fk8Ue)Kp4nmINo^3_p\6!\.Qok,NFK6D1?KSqUSc6UL\a28R>sa8PI.rCTGo+]]#82q4\uc1PS#Y>sZ1ms;#HfdrKq_[V2"O6IPn"Lc0P(cC_['\e&)A78j-WQsb>W]+TRB%?H8-6BZH+!rEYuj-UG>+7=rlAPq=Hh3P^_jP!=8n-2Ng/T]26\McFA*m-a2`<nVQoB,(aD,'p<t%6<p;\T4!ucaSNYkYZ98a7#W6a82LQ=DbO0,&3adA,?><ENUbXTL.\<?%]G`N&L\/u5eL%`5/"aF.I'^jl2f(Nq65XTbSYET:ZP+bp;=,u7MWut#=FfD#L"5V\`@RU#OF0);qKk%$!<53At'7f9Hj`Be>kn?&hHd\7,_XBB9on,E8\5k:oqa$"763m6O)BFpUd77G^BsBW6k9s'g9CK)GpA#])+8g5hB$u=YJ%t4[7.dq>WKa#\WH7hK#BPg..PK(dR?]1kM5?!d4Bi]2lQIaNRG-2\Au/8%oRI7u5fJG(J?Ilb3],5j%49[%_@JV%Y)gN[(8!b(/CV;hp<QCgZ'PV<'fPMnF_#1OtYiLYV4u]?ZTmoXFF`+pitq*J>PP$rI:4=lpP+1Di?Z@7W3tp1Q&dLc-@X04VZZKiQWSY,5g>F=mZHZQePCE(i]%d`q:l:8m*>c;KB^V^au#=f55]Occri1aChS!fQq``-,S(^'DZ8$7Zc7C1fn\d>.W\Rg$YBLIrS)R)<Kpdqjo>MIaR8R%gCop'CDQj+6em05D5<g($usDM\T05FA-D8%LTS#<F)5EB&/+,(--l:NR:8#mse#+c2ps.5m/A7AEFX/B20G)N7dXN,)=*Q![4.*$BECB?Yi7rrj81q<a)=TuVT^qt%:*,'aY^,V[X57GkrdfCY"mJKH`Xrcp[<%`m;PZk&^)TaE32W;;p$=G;#]R*o)a\QEgT4SpM.1h>;qaff^c2MsjI_'2lC]BhhBKc4@;?pJ?M=<6=BcSp8_C%j]EA[,''KCtIRE8"o/Q)"^_+Jf?uA7W[)A;5_(dfqMr,5pXn=`_%k)J0GZLsnc>70`E(nb=/2COM!;!_3M,c<q4=TJs[,=k+]!#-L,2R">k4LqBf#kWeYZTjclJY/mbQob.9i)W'AsR\ftfCnC.Vf\ms]Cc2]Ch<LRZRGCJd(WuVod7u5i;9gV\a1?IWZS(S*Ci,qb/SJL%@0L"\\B+\.\^jNEY7Aokm\K0L_Ahf1#S/7$#(FSPP[DpHM0g\cY=SZu-B(0G1FZVlc7lPnZ/`3_2ln6q75dNLZ7N&X,D/Z0jp3:%Uc5%&"Bo4#0f;s_d]s-BX0B(^'.EbBB"32]s+>-B4a.5X`:fMk<ZqcqV7ZHDr%S*CAXmPE<rn`@`k@u]Yof-@m[3b/F72g$SWA/cOms!KGe>gWdNST)CcE[b<Co_pP"6jd[q@Z/+k/PEQM5dVOn?cos'Bo)2#VdnYR<i&(.a%*,^,NU0#W'26-BMR:UcIjRNS>VK/ps'.`@AV3$mQT5gT&0N2L7%Y</<l6.Ab`H9&B@?21qm^H1erd^]im@::9pUgki0;;;!'b8X11oC'rmXKK.YY@KJ1%,sr9&-sJB@P@3%94PD_FM,rc62k#(#sl."0:#e/a3V,CE6r]9$GisGJan@:L1IZdOF\RCL)W$(D"i,>phX^Q3FU7?JJpR-F0*tl?X!'ho's+6k_BT746CE$jA&tf"-+;e+9Ln""F>33nS;Xh&-p9"Zfco.75I3u9H%c-o]]@MD)4%3Fd<I@*-tk!3R)!ABg!L3"T?$P\N"D7@lET(p=%9]mb+r2>[<cDU%T_s<bY<2FWUI=9@u]Fkgr*L%u7@=[Ith&f)$pVEPdjUa2r:[C+IPE,gIs/?,!V4Ad/aML6?+c7t`cuFud)1e__=3T^,A0<M$QpfW"Ob^Lq&1k3)43V0T\bT^ECiSFn[HfZ9f!gj/$'q*4->5*^<;0E!G^QQ+I<VdE\`)C4'TIG'0HU-S'gT^#?(M^uek*S(<c_2RgNO4EWJ=Ksb%/HgDfa6#WtYu#YLfa[^TNTI*^O?u7r]u=aHU^aR<dM=f#d**LCFrWsXNr#C5[s@.<8#F);(!c3$T):O=:S0RhXr9jX`14dW"7%!d@q?a&"IO9bKG[bUT4-l]BN=cZe4^KKaU'3Yoe:^@+*/.1.JOPqq@Di39DnBK:Z'S0L2`I]$W2.Y(n,@f,umpW$3';BU7r[h5Dgt$;=23)]F@)oR)#'K[/D)YnGR="I3^eeW;-j(`''%j,g;X1@"=jG5h]`Fa,:KKQt_BdZTA0G)EXN/K*I5#=p/s.Tq.ZB6SS?jkP^k";:)Slc"6hmFqI"p&kNZI&^qf4*j15;A,"qrPPqhJQpbS$[#f+Z@DL[Cr?5lUg%`60M@&^aP/'UprHXs.BR-bRGEkEj:?L:3THFMnln4hhLS,SQ;#>J/h>YhTT\t%GNES_@XP&6+oX9KaKXfkV0H(i3ZT&8Y2eZh+]nUBm6]'BM'EU[U_d0V8RDh&mWni2B&Z4T%Lep3uPd(Xb)%J_7_Jr6X@PCr,Ihpj-7u*>MH%^k@+OES7";7@JR]e$TTu2C#893QlKpbj4\\g[ikJP>i5fl@T[.k[5b@:JPfAPP&=J!\Xin2@9XM;Uc>8[Q#Wbb!!]RRhl"*mTGBXkVO+s58VIPB-qjF-],CE"2!W>d]QC7<+"<4+'?ZYZMr[^rlr:ZmDP4gJWu5S?rqr,H<VhE;$5L\F_`Abt"lLM4=k<B7Ye85ef4"N8*8[VPYOkG-Z)b)!*fhW*aRTT<RIA6_b2Q@j1G2cc*Y@7OI81(pP`D.k[O^)tX`(s_V>cGlLpVU"cX-:c.O&?_6_C#`U3gh<!qH0dF0Ni+YY*ST.d"+Foq?oS3j'21+8*?C(HZ.m09SSJ0Y`RN@C/7V*%&Cc:Gjrq1I>I"f$$=V:EB<XmVFd(%XV+s=0+bVDdjHLq"(>0srU#R)*^gQ`R,Fb&WrpNL:a)@o_@iKXW@TOsW,c[#lkt4bl)r,59bsu0'!W]Y3dtYntfU,Pl5flcL?D6"Ve%RXM65_#DO[>%X\8>rqBVb#_L"s&SdJf*b+OXa"F`^flZ/?NT92%e[YIp;r><s_,p=7KL5qG?^K&e+8Tm*3,-5I@kNkTsBi:_18lLd1BhTn0oF1<8W0T[Q5_F,#%_K+>U'6@b=*bied4Xsr\gdt'GW%#-,ZlCeQ5-Tq`l@p^?2W)XPk(sdq'KB)Ej,OTD%gMI&%a+!DSe%R5Zel+R#W97\kODiqqsnC%WE.5BbUspMcNih.1q1HTUN,`+Wq[to52Q.X&u/0m@(j5>k]:nfA;lpS9qHkT5en8NV3EeX@W,Sl\p$^ll9aI^jQs)X!lB411QE8-a8Sgd>ruMaa@\Jg=*rQ+We;ZdW.n&Bo[MTQ\K&_Em!5d&%HP>FLGs37*.Z$$:3^I7<G<MVah;0I1!&!1:ulg(&5b"17Ifoac6K!*+9BRRi%W?T]L-]g":T?tKOge5)*5.e4Hkl)-*,,n^r+qF*n9$a3t?!nHT#8JRN]_acu;_i%KY5G;%!E`#u-h.i_]d!Z55Ni=(Q_.gmgOdAF+Vm)SN9\UOaTiFD0*%86pf4kNMOB6eE(2b4t)08X.%.J\E&im7R5?S#6qn,)F^7*a2us-$)Pf73HSVd=]A*7'MrHSF[Z-l!ukoQg?&Q*M"aDfoU`U:-%"A1TT,IZ^'BAN/0e32n]pgAai)q&IcR[%'Z1U(`d!mE@HKI2[RJ)1nqC'-`p'g+OCo2_>h(:Ps[Nu&T6T<C`MP))201kZ_U'D]-,fe3p?5O;A>(U'p__8']56IJ\i84QRNtgO++g\2It744eu<0W^pg!>76ZaKY$@s&2;M6VLh8'R$(aNUa/qRU"CondIBAm6',It&MP6faC='?33lVJ!IKl:\/eE;HkX0Z]nTC=>*tOnK>LAl*^L>re?T1>*W2F_A+uHT6UMfL".0670G,QF4^R^iXR4*PG:b`cn_*&J*o$ioL,a3'Ag-/;mJ&M+&>'t?lXjb9noAQ,GhH3"`4]h@]GX2[GRaslOi2DW88b!WUMr0n5?JR'*0!M,Ar3g#X<\,8o(GqK_fkPnj0Qe@[]/*R#mhDW>1&m=9BuClFS4i%=.,S0,[(]H?GbhAk!>/9U`gsUodRuJ^V6mO5pkjuGiL;'<E3TbYcg)#&e\K`4!!FrO,+#B@8G/A*.<,'OgfIgc=Z_oh:XrkK*Io.'+kfg*\R=He!`Ku`ZcDO\9JNsX2(XYS`%C7'M-T*s%#>OE=%aHq>poU%?Z1^]P[r_XP_1`*O[iW@EC?$c0/Jh!_lm%>Bo+h_ehK)IqER(6\iHuOY7oQEK=2.i,9!Y1O+2Q=ko+HWmOp:fkEBhF0I*U_Es?O`\:Dd+Y]CA9dQ)B?t,3p4NH*7fKgboHp+1=BW*7ZK_*S'@W8LnfJ#2ifK9<^P"[DdFRBRQln^%0_M!%;k5^$ToKS&ZBX)<Nb,W!kl9u$37L*EOQf;'+-K=VN3Lfoi.d@^Y=D)LsEsO+V^psmEDn,PTBK.]?!c/W0L=4Kr<5HT/Q*^!N__TF+Uh+;.CI@-7NAYAY]Y>a%O,K$M;Il<]C/MY<ZsF+5G=hlO-#Q^83ZFM^9.?MA\(rqek0K4t!ki-nHC-p-LCc[<I5_("4.^nng3`l\`p)s\$&RX_r(q53r0bLg?fk?<n+@[h)EKa^:.`eU3Q\#F:s:PQm5%-Xjf\Ocgf6ge)K+Jh<(-H,oq$G3`Ve`Le.b.sM.qP[LgQ/Ee#o%D4Ok?Ia2*a>kVefP[2AS1^PB93ZlDU05D+90LA#"u&SS.OI:%4(\c`Fq4AY/;d\bjEi/<h^CdLAm2BV`mkKg?(R[\5A_rXC0kq''T'oB:Rj2Y>O"b6t!;Oba[msgA9B2=`c_A(HaYZ3r>WC$k]#p6?TPQ;cf=qIDh`WZE?6q%h4-g,Rlq[guiR#?N>%p,c_H*)J8/o,dLU^t+f-6L_8&g'aI,+s2KUS,(aDPu\Q%PS'>"RrfBaF(Uhm@^0q?a!popL"3'g,i8#6u,1lO9[ZOj?9Lj`b)gJ85r'Od+sInDt`/E#5I+U"g#SE].uLM,rUk1+gZE&#PMVb5Q_$,9BDs^@>"k4Ops*t%-UY=fZ>][QSQS](_L/B'"#V)+C'IK\$E/FR$jY3jA-,S[!go-%Kg^U,^P36]Hp'G=r"c?3LT6Hb[S@.4?jB6%:gAXpiO@$_%9W>eESMkd?$N-(jjpS;(P?K5XYG;PB:$aM%&,F_1*;h3ctt0f%bug!UqES/..f*jUUdF&#oH`Z^PXq4m3:O"=4=+I_po&!Z@Y]kceNI_9ft=^JhUlO7UN!8C@rA6pkf[ZsqV#b?F8?E[u1b7CA$(/Q>q#WD+;(`i.Wl(9t+eXACZ?Li>lb82*9,;u>l#5S$RO7=N@O.]*`;EC\40:#fp&cu;]oL56DZ_9.lk"YHC'1'L';K1+r#Sqn<ZHg:DjVd[s3X"]E8[R1aB(6e0A":^Y>gB9JY%ZhqBY3#Y5Q&#K1+i@\T^Y@hbP"9'h'EZV-j-Z1KD@q1+++s^RnN79mGjLP@62Sk]J.)U3:;)BNd!`ddnst=4YpjbX;Z5Lq05Qq!ZK#$"B3"i?T&W=`)=B:MW6>5hoNu`df/+1`8CAe;YG^?Sog\-a=[<W6T@G3=LZK^t+t/3,NN\Ghe#4%+?+o/@YQaDT`40DUI,Ys]2IIKIAOYU.$jOWnZiR]:/g70FTMXF!J:jJdAop39lP-^V;QV't6.g[iha-FGrth#gnirdK+j6i+49dm?"UG>'kPP2@HcSMq_AH8riU&e*EmrtTH`f<KeDY$6]Hr;nbPL9eK[Mh>b+oB#,3,[NI/QULn6%/"4^""F\0K20LZd2bTjQGJh6XSi!n)o<clp12oMd),m\K]R^G;CoPn4TsP"@t]O,)I1M;2NjK4%5NFj^XGOVZq:o.RmC^R15rj,FLu@)-1WCCoQY*5h(2;C6r.^2[t(MdmDXP>&*UR\Wj^8?e&SU')$l!]$P_9cPf@<W!Ot5sohe:I+K'KFVI9LZD+$s%hnBh%1UH-9bK>'-Ve!J`-g;km*rVqk\dOK'ihjrrD+8'NA3S]'VN)gMW6FgSo,,SO6&F7mhO7DI1EuA%P:sf[C!3,(cp2`>`8rKSdX'(dUG87M(eTClk$I!,ZX$+!&02\J++i+ohbAV,:o>8jHIF!Ruf.QS*2',e93e&kq!bfE`9jJHPQUT95P+&L7MWi/..;+J-87]2@LBMGX4.phL>N]"eknStI=$[`J4ti(mn[P:r:<%oDL3!Jq$!EGGPu+?o"L#'nW2%!d5"58XX:+lr_4`#f7-RVYTsC0N)'_+K.&%jd[e+mB*ji*lipTmqgY#j`2%bWp(MaT""`"Ebgu,+ul34tfl_>jG\H/VtZr_96CgOMh6+AfAUKpBqc(57.Ve8VN!$cMc<,=>MUYF1J^COl216MtC^_5eG$I<=HSoeDUlU<ABGHK5%V.6l^e<P'A0rg]Pp]#!F)'eZPft+@*aM+OT<irsr6M/soiY[qT<iH\Z:)1EU5LO+4==Z0^*-O,,85q`tf^P_?u,O[/HtqQQ**Y\]&BZLq,Wlk-lZgA+nrXc17^L@IbgbImD-k*m;D40)4bCA>^R!?WF5UjJ9M1S@[crpbF+hmkO9:JT4i!rqtE?gRl<U;$V:8g``g^LK87c>,3mke%A42+<u'%L9ECU5.#-+`,!3:r\?K1.ebq)<mb9[\aUVrlCfQQ.@)dU,4@J(V?lPl.@3o?%@'-Rt75D/UqP*hiP2n-KmETmb^>0IC=R0)$SY`-LjOtMO%/el?K"4G;N&Q*0!:D('&gH#LhO^nY3@-SN(s7-,+==Zo!XrGr@HNa(F1#h\5V2fY%n#U-&?,fJA^tifr#p9dhQ`O15'c)b+7r86HJ,j1d]V1/1WVX$E*6dq6`UJlQIdgn2<3%`tuHn;[5=#dYj2\_Y/SkqS_j*eq]h[fqhtD%fZ*CnKd?o8fZTpUbJTLB?!%0^(TS5lS4+oEU1k*AXZ]2j]e+olBTfOqHBcNFrG;XS?,_Df&rX;G]_BZr/$0a(sn81D`+"hpuBIR(DR2aC5^;H71JcOf?\$GjmA4G]g]DD;fkS7qb%JbW2Z3P45fF%<X-Do`!hT9/aurHUVO>;']>b+!E!6cJ/0l0T-pZ70OOb^mZ.#G<%$bZ*q4K-0X+K1D>>ST-6B]B\KZQ2:Q6R4.esJBbO135gP[+>DV1+SjsG[KWtf.<HoK%OP,l?g4"\NaECu38k*,j/8RA`oTf]sXtNbbOrn":L%ENkm.^$;Ri$K(P_l&&WVC<i/u-L=jaS_dK.*O35shr1E@7buXDpn6#i!*=2TXKgV:-=+Sg?=<DY^qqqj6%/%/Od?UjI3"QU4u26^t_?'&7;BGDL@g/-B?,NA2S)q$'uXis&Il)=;MZ;UhEL6Dt$aPE9,2EV306O:`L<nKE`;8p(,S=Lj&oTG`njQOd[@k!p<U3RL5HG')d89d<4N,Z3SF'802#=c.Su'[fUk-UY]\2%q-ikLai,<XK*G!:5N,S0Ud#X=/-c3,agL>A-LB5:$$9&n4pb.ZnLhJ;uli<H"1^efnV6_Kp@i0Ka*'Sq-lbgGGSXniX1,Glo^Z4Ehg$d`[l$'k3`0I9fTTB;hEPqDi`s[`lss@]K]Qe:Q:1in60M-Z7\<Ak$9gJIESPc3OV_(+YC^!#\6A-lN.F69PM$L`Y$Q",`7pC('E\=p`BNLV\?3hp)pK3WuV33u,E<deRI8&@o12D_0*Ac4j,`1NN[.lnBLE&gS_H7PLBM6*7K*]2GM_H\M7N>r'Nm1Sflb5a+l0f@3gDX>O[;p@[]OB.kmb)o_`qM4LQ&&I5`+-[4-?9Mn<YG,M\3W:^j1MNLg@YCP1O]IRjM3'nCJ6[Wahcr=E=T_npRAM$c!\T;0$oYqh^iJ^(-K3:q<cb:,PMrj,&0j@ui[s&8EmIAt:pH[:B+X4'UOfG?u4hi4/-P6R8cTB*_D,R>^;OeG8N^S$q<\W->R9Tl)XXtD?`&_N@8":>KB/%\C>]Q^gL-6\GQ;NpO!mind7I;cB+A]8)ktpY-b]VU.E-=<$3-Wr/V:dik!ZlXR,AGmsEb(9$'KSf_LqA5Z6]HfHL56^F>Tfk@jER]rBjR(XEk5sS6&[gdQ!O)/0=q4'PcVY/3%S\C`^'_3ja2=OPD;VuN0*f?6Bu#q(_q6:I]?4QJeLSII>'rQqF7N$]:*\S<c8eVS=OdAIfS\0#pAksp]%CW8n_Z`6?`C5Att4$M2GfE59D$/O2/E.+@M`*2PdkcSK3KR6L1l`drt:cC3`L4moLqU--DdN08<Te+!aCWGN<"Qan\qRbr@&l'6LlRO'Xi<m'S(+G0QLi[\?`\dZn5:EXk<64lX"f!K[DDVKUmcW5`CH@#-%>f3tc2l\k#q;t<NHT4"Yl$1gY6r*J(K[WhLmFfQl8Y?_Vd'WY!BR`u1gM9p"R&n`)`6>WE18Vr]ca6`?BGib+tGs6er7gG1JL[#gF5q#^CJ.jar&I`/H`9jpK.*ZUM\P46*ZU9P:F/oY8%EhFD#<l$L*6SmSb/)7f]tu8T9H=\]:n"<q$ma%_=bDgn>%WkhQU$fT7Ps.f-lWpAe1St=WM2C0#Jg*H#(D"6nIW.UB.b#(r<[fdJIeR1qS)&!Ku,RcqcUj/q9`?t[5D:AYW+>j%@7oT(HtY]lrV(91b'('63P&\;iEn$NJhWOm2Iq2<iYrl*2na6kfl(NK8<pW!4<EOl#SQ,`s*8X0PKN\K>?!n(sL,SOP82CKfYMNgQB6Vq66OKL_06G>FI>2E=*/d6]Ntu9%+#KRU=FB',nGZrZ/-CCE1e#+V&HAX;VcM+Y-&alXiOI+#aTO'H_dMmlq>hTX-.9GEOb:6&gjZKGr>Iq<tAD07-+l[c\84fc63q6[@8uAhY+?:iG(/0b*jO^s>4"k6\k6'542!'C$`A3IHB3d8f:/X@saI"8uS;<MZQ&#S;Y+ljX[7R@"aj#^_f^jP]cR_g(:A_,Hlq[:>4pk^t#1RW3p*9[lI==ffgT0tK<@&8/CEFh$Era@(V*c*aDp?d?PVI9^",2!d3^Air)?-TL=%Bo]/BB"5\aC458>r&BVHS8qlKNd,p65t-gPLh=]=@Te\QCJ=/l7H!FP9;T/:X"\B0#6rl/7B]D4p6;k8^,ZgQjfGGa>(--D;dpWASBG\r":pdOH6F.BLZZf7LKaf)C*W$g=jVdJ,-P!(MLK=J[5eXXbDM18jLPoN7[DVpJpBPQrOcpAa5o!P:JCpNK><3DQ6sLZE'WfK?*dA[5h)KdM5\fe>&lNCRl_%;];K/8p^dYRODhYj&]<_sR-=!<n3!(.7Y?DK:KP'i]spnc9am-n!uSW-*a'\TN(^LXCqTQ>mk#200tS[Ihi,Ei$K8VcMFA[+#a*0\e.9I+65+Y=cbQsKf:"(Nj`]>)[)>.Zh\IXA%Nq?#eFIc7-^KHJ<pD@So)9fKX*FBR3(Sn$iF&5i"5e&BH-+tErWFLP+;CboK8<D=1aOUq5_=]aTMY^I5.\,:4Ln[e1R!WL;Z#B$BYn-,/+D1IGg48d6ZWaeYU6>Z&iO@$!iFPn^[?N&e0&SlM;i]Dn>\CK-&kBgdAYbV@bON*bVh23'-Xa:aJdWBM0-or/6cYlRMhnFZ;`/.'L=G"=H&4a7$Xj3Ai/(iM]3qYAYRj)6m]QF6S!d"SHTEb3#W'2^g\THh"5fh>=roBl6!Cs&VIUpZlE1Kn"GR=_+1:Jd6,W$W%k(2U)6]gX;KP(6.Z3,N[]f^?6hmR,!IiY,6B/X]+*,DJ_c,q<lQQ;R6<JYG`37TD7'fX/>5^3VH2e)A1O!R+?-8G6)bOJ@pSU4#g7Z"PFY^XJ#M)TCPK8b3C/CXf708.>"^3\E`s@`0Ye1u]hgL`<;-X?.$B/fKplSM."[=S+I4*gp']LuOa1AoA!Gn?85OSd(pSE'n'H:RqVpua#4*$9"Cbb]\PsQE*$t,OT_Z%`*ZjDo45'#Q?1YiIf#3u7lR;(k<X]Du]s"jcXbR[3I@@tS<Usa'";[(B2e_UVE^V``F$*"-I=dcN;MG[$*-:`M3Q_1>kMr25;hZCb90>/14S^<&qTrR`);X!:[Hd="EN"Lh;m4F$%>q^2l9oLW[1qjm\n!b'%2c@`*&Mj_)V'g:7Kk##\O!F_IU.6^n8F(=h0-F!DX(l5\1I/,P43C.)bmS:321&"Wb5^uCq\e:Cfjs.:.)b=oJ8J8*/?juKRMjm=ec>g`tY:c`5BW$<&;1NP%tNLCl:nS2[q-lcr#CP%LAS9TK#!OEI%.N`R@UBi\`kNK4>!=%1NS*.Bmn=8:ek.[BE(jMIfM_)Af`ZiWINLp/E%rm!!*XHUu":9:a`_rPhWg5V;Q#oCkD\mWXpb<?6LXG//L=hC%d6"moSt$O[cA4^2_M`Nk\jS-JL0cm@@(Q&&sc6/hE-Ga\FP_p&=+-f);T>n2b"^JfFC*h9$m#JU$jHX^Ze'\Me2k&dQgd."8jH[^;m7mXMt1$%X;dUTe-nNo^5e/S`A/d`e#7QKgB^clX@c\_V(LZ^i:Am]gIq)u8"Br#5kYc,pc0Old^(rOqQUTLV0l<$3W(gTD<+>p4$?]3?@;B7_G+k8R=X5uaAa>%"C)6#JSfD9d4)AuJfAC'fqCjQFTo^oCe\X^8N7Z\q)Bru#7Of7#/YIX==:3Xu`>KbQqXE-"bA@X42G-bASPJ523/fE77f,X9/_Rmm\FS+;66)^$?$>r6Y,2fiY,sWY+l,=(Y0jg3fKYIiHC@V1(<SkfWB^IqQbij+d;A6Yd3S;RB$MRfTpOkVO9J7Vb:G0Zp!i?8Lc=kmW&Lce^Bm*n&_`-)PFM]gb`U,>!_=2'G)k*/#A=/#Q^rd_$9-b[m'[O7$-SAPY$"1Ph#;n\?g+@?32e't=E:4%!BN-,pX&(Z-_m)@b2J]c-]OeW+no-?HBSA&Q4,:SH6!Q54d8anWOK99TaCJU`@Gc]Cd*SF)N"gKjS^]DC'>8B%arXa4]*K\qfoBR&8:_4T'dSaTjXgSa_QlZPOT%`jWG]$..q<&??.@@q:BVO]$efJ8VQ=s=G&j$c`o'>pI(7".]D4Lnp=8K@5qgJK%9cs%U7Z/*-#phk3Q"dWo&j2*WLQP6cmIX+*+%Td/9+-F_Fp+cFI6REE84h9Coa-sKYql%XpW8,&#do6"-/85@Zs[N<RKEWQ9]/i$tL=ZC/AZp/*"jADTmZ,,ID#MG9`^)d%V*1/s@:H1Ud],KVb4-7SWG*5;C.N<B^!KaQ8pgb%AT.OIU16<5<@_gf'#UDW0`;TUk44ET1oVU9@ltqYAa/4;F(3A9h&&l=An#YL:Sf>0#\6qi-FdKt(-mLWat5gXM!jf]CsTgBes][t*E*(I=_q)"MisX2,[E=53l8$/PHVbC/r6^rYq\`9E%rOlG;\oLs(>1Z5qj!bl+:T),nNbV\'&o,u*p7E7j^:fQ7\bggN7UN_)G_j:t!3lNnXGdhSC*Op4!=XHM#aDMQN<(0k/_elDk]/EGsU=bdml6S2F73`;9$).K/78IDrZkTbP-/2"q*SJg/DC;KG,DL&Wkrd4FlWRki7f&g[h59_G^GWHC:WgL"`[@)&^aJ)44Rb/%F>3W5r:'2"[9?<fC*olNWOO7^/9<$mAp3,k[!#ZiK8:j(.uk$<gFntLe;-F&WrRJ+8oF!mY^usYV.e6GChUt,QTLJ=Y6PQ!K/u8s3neA$gh9j;(eYX'MA59Je<:!a(<@(?d#oC\\[mC9Rbc^s!lKhR3:oU@]2<OnO*8f@(DN(N574ks.'1!n@;4J`H?YiPnDma&4ksPJH02`9<_[\7jW+ofW"c/B6QB%7'QU:47^%Ns./7D_r"#D&G.ak]W?43Vng<jJ[toQc1uRaad<BqGY!g)94(d>CI:3-\BYiVT3iF=cNP1.a&;rka7ia;mabPn9.lF>3bA`ID:jCf[>jFL!`E9X`7'R`bV#iBlOOVJlO;md/eUb.]Lcep&iP+5)QADO^^+G<fmLa1X,+^^_l++ORnE+-!6X*b)#t&PMY![NTlQ3Us<7I?[#:#_BaQ>Ch.0]pV1M-eOTRj2,RX1XV>8m]G]#gb;BuL)@*Va*LdobOYe%0&p3XD7+FOMD1O!_EAa#up=6dF])G%X]V\t`]Q3)R<J6oL/sP,AAnQp[nD]/sR:,RqY!*73_&!64rI[!uOT#-nl(H)&\N*kDp([U>(]C%L$*nSmpYiNQ9BZkaP]&d'SE0LDPr"2B36HJ:IsI'Jq17b"`%mI&n28LZde.(7+TYR1dn@!Std.UZni%MhH%2D%[0.oD7Y1;t+LIQdn0#+HQKT3Rh:2e"nBZe:+MS(CuD,.&8!@[:?I_bmt?iZ#)72bun`p;1<lRYRb`#-6t3QKG`TS"r+Sn$uaOBON!#9MULegbOJmo%'th\YbCr(QN"_^-kB=:DdMo(M/\uY2-A?UgZ[rkAN^K]Kr6Dk<r;ZCd_N_e44+bSS#4=F;:rhR7^hN1_+H8l<`5:i=&(?*8*oT802"Q>m-n*Z@b`J*&))_hc*-Qh5`H\YY$R:f,-L!(r_p[Yld?fb3Di'0U#P5N^@10L&nUE3,JlnpS0i-(G5m8N=k9'fP7C+$ne)l2OGVF]31rRc:0fo>Nsu$F*4?/[$;+8csW/KhPh,Z>%Vao+e245P?eD'A>-500I1lf5o'Vlf6S26fuGW#n)!.![F[-p!0"eh?L3bMOA)1+fe^k]M?<t)330U%GV2GojXmj/l&Z41@V(trUnEIK%4!;7,49@?2U:6\:!O0CF)IN&V1QK7ooP>J@-e5%G]%1(J\e\'"'bu=fe0oC$.u0f]n6['"mEah_E\BPs&g9/:Y3Z":-,!>apPEg3Y%?nFkhSN!$6>+o,7O^HfuG<PsFL65AF)h:8&SZ,U,c(&>E]MMA^\J^(k+^gGD7mQ_I18'"4+>p`29Z#"*ta8@pAH[J;22)QMN:`*L$nK3,N%'$bkpZWfdA-1=Yoi,"LIkO6"DT&/L7(Lm"a%J`L)8sHVoNoe4P4-(L$6UOT2<bh_3,k,p4R^:&a@2#W5`gZ)%4fb$XCE^kB!EVu$Fp&q-6dr2@Vb"C25[Hj7_;#&=@k6*lcZ;2LJ-`(?,Xt<m_?WshW"Ot">ppU*RCT[LR,JN/E<.ZCO?3s@[ljJ%)#AD+!f43+0oLs'H9rqs'1U@`6/W6=)?E5q_6Ee:r4n0d8J2Z(+o6>=)C.Y&qd*r\r*XlI'<$]]WKqUS=u7GgM6QFI>C\*i^$I'R=LFgC+X,bo\bA/W9-)Xq`EtEo!G!82`0ibPB?ue!n$HS:I*g#MQumHpG?ap&='fq@o^V?a^3o1.1n1Jg;+/b6JNFaM6:R.o*dBf+S9,G]TVU$#HVjSnUWm8B=Z6Z^]P/BG_QQF/8lU(/qFMAZ4NKUDJd$F)rM,Gq4ujAoT3p14&B<VfMF]"Xb\1CH<[VNdL7BTc4Fg3SGTG9dCf\cTXBC8on\fk/e>m>o%?kRY2$RPZYo0Xf/;$EdMBL,H>pD2Fpl?nF\9;aWZ&eD[hJ?k>&l_I9L(s*pr"+f^BnqZo[UDVt5\@>1$*t#Z/2Rts5YUT_Z%f];_K'h([_t\:iBVpu0+V0-jTEW'cE+;[D7\i\='aRI6^I(_GB,"_&FQ]XR28IW*a7lF`ieXN\o=%G8n@eSGZBeccJ5\E^&NLd;anbH$#$9a;"ZX<)VZ"t,MtY0@=HGNa$;S*\Uf)anRNfkY5<a]8>d@>PWJ]MeO6f"9=2<$"gf&WnEbaj@;<4W>aVH]2.BXiXuDB>B@V@c4oT=rPaOB%ldDt8a-X]R^g`,V\:iRmNTm8E'9>M570sShf`Edm4<LTkc)`$lh%[Q11b;':,q$JQg)jidH%ioWLtMiuBqRf1W\an6'So[[P^YI<pR]4DinP-NmNA7@#fnJ6(ZrQ19LgZs`&:Y>`W[]ZG@qLC8KMnM@0?<-6,hYR@94Fa"',L3MK>\sb=FAt<m2b_*hXl&Nq0X+_DZ<gU,/3$pYlRs'DT*-V,'2jMF(nd;C"Vl2C>)qQmf*o4',1'$]t!<;`r=oD,AY"DhG;kgi5:\PBFP_%^t$9@V@Xpl.*>caJ&eo!M_3;&l$HCii_cZ_i<%hVAk*6[L#Xi>gk!:NSm/;S]lE/nj**@)TQ7?S/jai-CLB3F^n7h*73qZ<@_Mc"q(pB4;_,X)R9@k.-PjZO9/Rl)@P/2W@oLoJ@a)S/416D-[)Cr\iI>s1k`lu"%!kJ#7rg\p^sln"@Srk(dCKS/o>u7U%Y*BCfg47Ql7GOl,T(5OeHk7;ZL>=gV$Xcd]EcfjM%7?04PC,"N;&m0kFFQ1G3*AhR"%F$5*9YJk.<3kRY2Maf?J;YG%TTNVo,]SUF*N/n-08.qOicgba"J4tiHOoP.Yqp?`P.?+bYGEc"@$QSTgGLhLG\#9#^Dk9,^DAL+9o*@T,MQr`4)[+%"lW-8A:Mf&`&]$JZko&"=,DF--QWb/&a5`Li@(e`+-_6hS?<&74K210E`@Dt3@NJuZ:>`oo/\UfrF[.\'1)&;5CbW4N1-Kupp`nUcK*'.c.XslK,*h,'\cD/YC/0lh<cB]K2Bsl6H8!BcQCWeS/*HLjB1E0j\Cr3$)@1`cq`c=.BK9kq-2cpH(@G$^5Jc"E.!Q`'G\?Vl@,U.hH&I);_i*WWPi(/t/Gt?J?HOQ2FC"8W+0J+NVJVZ]CW%gDj(BGs_-%ZVWEX.tF6Yj^SdL$lr`sMjK*\^3?6qWKHe"nfE"t'\<'r>"ELnU+<&s+_O?;e2s1,d-R32q+*@l%:6*DT5T@JIGg3])D`L4h<U[4P$GD(VKj<gI,2L^Jm:6'A7/M=3Y6U!qX)+EJ[2&gtkO_.:PpKH-'<lE2]PpkS:a$ONCV&R_UFrLLaNJ[5pKHg!Nr5Q_V9fDHBV%4FhUc@bP$%`f`s\=i:#p^fR7H]Nr:@f9hPFYOUEP%EJe)*PeQ]0TCC&:XZ&^u.G@59?&*A9r_>!tnUQYd=Qj+e)o'Kdd3CTqIi3!Ys2.i11jHd!$KBd;Be")[<(.J4]J_lN:G+S+U=EB^"MqSIEDGU%oT:!_rZs'3.sBRo@.O7jIOWQgUT8mbpG1[^[*I7Pp]VCUO3r]g@'BM@:kEnr,KO>%N>)`ATR]Q[&`TF/ZPB!5IZJ5o?h^^4(jQ4]jC4TTp?nkkY3aT>Fl!buZFoNr0pq*&>MOHPf\9VWR5o1^IV;0[3/-"!H#;8l.bu!A_s*'[3joijRYURo3rm9f9CtY$)U+Ra%q0fd)bje3OHn1:.t?&;;HrPt>B:2Hl)g>BSS`M)/9MLm0ca&jd[HG\[Lt$=JN=K,5D*&qlo];^VdBQ;l,44S-S78d^t\P?ScfWCi=WgIg%/aB<AKC.WJi[<9d9G$>8%YaH=5((2Ps7]auS+X1-?NSL;`*][7i8DRiD*&dncm[T;$KmC\nkSXeaR$:'.`h;KV7tCm-66aD&!94:e,a9@3,%R?@,=-"Zj%G[`JfNkdd38d!6V>^iJ=i0%GhXtg:u[WdW'X>CJLYJ%W<@km#)8E\"qpV>-k6hh1+F!2*CrOA>;9=01oi0s/XY4j1t'd-g<*QeD&JWY;%a9MKLCb%W(IRCQ$8A?/-,a(9):l,KIET,$>Q@;0SN6<751DA&2B7[+Xo]L6"t"3i!oA=F#TC?d+T8eG3e.0"#+P_&N+2k[%nLLnILDn_ai)\KiEDWlJgLR7qcpE)H4,T@3f*;<gAY:R4WHb"J]<d%)b\5?<D`nO\[8hfBmGAk;+;oD-f^fYa7]ph^IfqfU@Ym*j:1F:UmZ=`$WkR!-[2?%M%u<GCH7F.&FFJInt4Z0HLetB@]63I)&fUrAp3Yo!oHJkV2Mk#E,]0g(\9C7qP9-HL&)Vf'Ts1DfNZ*%PW6ue$Wk])IJ8^r+4)3CUA_-K]<0bdh:C%=@b=9I']eC^ZtUZAt$t\W$%C8"C*<AHc)6"r3t,X)g/t*r#B7:(u6)TLl&sb.6a-Jbf9c3F=0FI=sc-`MlujPn0^A)oe^.Q1uAQi7qk"?)PqCec!WQ)2D.9%\`aV(F!h0OCc2Sld7ac?OGP8S'KQX2-]s:65S;@W\mDtiim3ql79)6TL(GLT8#ls-o5d6[j\h3a?pt2rN4.c+J.K4DA<a"^e;)k'An5%#:F&lUYI+t28\FT"JXXRr,=HLJ*[c<l$/'L=6IHL;C7X[][*HY>?o1eTmX4AKVP$6Bie;RtRt0m%H^700DDl`-)o2$Hh=MYRj[CU`64a]YLnBD>-:$"O,6JHr.W#lVU(f;MUrZJQ^G_9l-oTF\20c9$P@f#DZ^#QFgTKB<fe151;2-\AN/^RK,n0B,r!c@H&!MD+XTsm0bW@GR7[<Io4441!/64r)!Q4*>i,K^Qok[[)-SP@Z!39.S$UJN03'rG31g$SMQk4Y9_YG7TK)?ERnee$HNmIO]2O`2e/Z]f0*?JXNc^=u.lqM^Y(_LJ3#P%W?mQ67FI]k9]22E5f/S(ibr9T^d0L&^V%"ga:P(_ja',WM7aC,i<WuPb)4ZJEaZG4<A'klQpPu`pu&OGZCObhn`&M\lZ8.m8%DVQX6"u=$(%NSQ&ZM$lp0/Y(-'<Ns'@p::>7_J&q@2hc\)NU;&,E[q"=jt%7Mpuf^R8IckX[%'hI2SK:2GTk[$h!8eW(k^^&He1GdUPYg3a>-c=tHZY<4%NqWM&fj;e`_s_;13T\S!KdhP>)+$chhll>mGfZa6EcM5I$8nqsdV);%f"(uG4HfAl+3KQ5T$aPA!"&>KAmRn.TUYbYc=_8aV,0>6Y*1m6459c1p/:m+/-f]=T%Eu',qd!EN!`qTkWZ.1GM2i?k5&eTRNp^8<(i$kf8Xb`0r1tIfDKgT#f+":AO2Oc7Um5gp.E#]g+"buI`)+$t@AK83R)]l&,1M364<^g/$DeLRh3nt1"E"(=MAO9:2&F6^@/XWTuqrPZs>4*&li\-:BA4!I$egt`:i-R8a,A*Ve#T-Nm#3Z;:p0l.R[*u28Am/H4oS8ZLR'0f3\IJo#('7/pP!X)ImSOU]<(#QSi9AsY+kl5S?8lae=a;@[JIkgX:KY[Leg2/L\W8K+^@*kn/F\6.\>/X6"L)KXK>3aG7n)ZY;dIt>:Br0pRZRBZS9T\-pr@E$LMTF&ChMTs,V#`DLM+5ij?7ZaYHe<HO=1hI44Bl2*>^G^DYQkoLs(@2A/CNlDk\404GUcnQQXDCW[K!A/FUJW87o,'^s!3C*#U44-$\1AdnHT`?*7"=7S#eOL_>MHVrEVD_md-=G2=7S9t+sR<Y4sAY^U$$\P=L>0HP?tbULUg#/"FgY.IQ"(gPr#6mG9t$/2@L0eoQF2=kRK8&>,X&/6MU@<],S7\qH]ghWeSG;Y:]+9^b7\X3Rd%1/+A6g&!J$`Of^%#`WU)%Vr:WQX@+7O8$k0EF(FS5b)@FR\4\J,2.oSR/C4A1>6"WW=!bX=Qeh,sW#/"*M';0o+[D&[j7kCWZl%/Zk]Z^dOU"[T7<\+[EC^`C\HB=u<9d-m9OIRLY?>1Vb,FhX)K-&fh@qUp\fVr>1c=9?m*2&)'*&-L#N<FP\A[*U&]B2]0T$35,SJ*s9/O#WESbD7NQfOL^_mY!?No#\9#>IJf]+cRW1ghp#Fpk2D;p\0k3M)2</6r34PB0SgZuMZNu'2H(@r46E;^?]Rot<+EF]G`:_qV#_"?D5Y<1$_.[f#5ZqC1d5%dd"k%Y6oblGNI\F6J-pc&5@_usi>/qS!Ea8<6")\e.&"2#=Xj<e5;%/&Vaj76,U?2Rn*CV;Y,b#@#Aq$ggEYT'l'G,%HiKeq@LOXMrE13$jTQ;#@74D<&bGr"(<A;8Mepf;S7*J,HgQ&c6S^rb"UCi0hO\\YRIeM%WeGQI^%hCWjPu206^!Y=6BNX61KCm]*&p45$CqHBa\q>j#-t5S0GeY?Rm]=hle(K!-XH#soT^3__&u_lVAL"i55bY5H\u9d4+M;O%o_!Y7/C=fTEkN.q@JOQ&lCSUj<q.8a-^1D\qu2B&V_@-aR"j_mlqJh:YnJRgqi8H1E-t)LJ+j`/d0"@+$6\<AC*d^9?s/XR*iO!8G:9-8LSdNRGj\!A$O7I!Q&1Q_j]S,3UFKk0+U93QV&a+@M>q$+DD`T_f]7.D/GmFn34SG$(QkD;a=T?<"\g](YW92c$QkJ/gOm8Lc$&!#8kZQHa(MB(l\Z+iWd)BWf1%6B3f\A0=BtkY?(@Cf4PUb,BKR=qMO%Uo@I;-:!9#),?-sSmU`YcNX!stL1F4T+5tEdh\16Vl:.$PCebQhb1@QKVUB'kW?>0qQ`N.])M3u<]GcrtUM)O),KehQ")BA@Q-,DVFot_ECOEu#OJSarJ9E36&s+qMF&gLhl#l/innm%`>`/&>PZd<6?7tDh%dV..Q#fc"Z%h#&/r3#G[kuMIV(Dd?m**Tk5iJe"a=53Pemh1F=<PKi#a5<g+c:=WS[G1dUNE"3Ou72]X<L,fh3Umh(ppS[jkP[3$77L!akf!A>,Sl!8G+k:YbL_Y06hhNZl/N4bcjtG=\FKW.N9&$2T3D%RN6thW@E!ZfX>8YMZSLIL''k170/)XOAQp'YRG=c+F[-K?KdZ1Tr*\tW0ZsDV_C2aqht[W?_n55Ib6'I+^,X()?=/uBUOTCJlerWqZ.V&#lrW#M$F\l@PgKPX:!GoJKVi\5`&6&3?s3>@^)pQJf#sA$ET8^?kP12^hFh*RQ)JmI/n3rS_<W&bR`,f8@3X:Xq'XcaSZ]k;Zf7(m0YM'M3\b]\hK*YMRYJXQBJ+9oW8*];RV+X0poni.qmKg$XBoe/TS.`^[`fB`lg(7r\hY("m'%GnHY,HJq?U(pcCT"P3VG0(+)184t4pQkrYat2?82_'f%%b#?$(5OsNK[hDgHbg,-lk'7ne2Or?UD?j?tiJCKHe,Kr#5VMHE%aV-*'8aI(ifZ(ai#K)W8^KJ[5f+[$<_bbG9S.;Q!+*mPXUA3Mkcf$ntSR$Ar""X_8Y?oLV7mApi4Lm-`L'%+/b7SpFJ;b+kkN<f"9crtfC_K#C][U'61<Gb_b-/M+G"U4Q8lA\JPVk5N6T!J[+I+e4B$+\I5-'VM9JH(LB4a\%#jIaicNHMi[s.H3Ze)#iU)qj?[>o*e2PED,BqOgp-H'htXu>79A;4q/>"+W0"PG[oh6knWPuo@7."J\"<-g5C:8LG^0T^i"Dh?Ao6G`+_&&l7`TThs.HkVRY_0lgV\;"H@EDT"dl^dY(GooZ__?j,;L/C(oM&98=N+&W]/86>nPIC-]&^ABK0-8k^qJj_N+sPYu4`b]moknC>7cf_$fJX]^doH:l*P/E1j9Y[@FTU$l(GdX(k[TQ(HXOgR?qOMW>p(EMqKP#7#rb3-@ASTOQij3Gl^WXkP#XYF'>-=e>e6?m'^M:nk5`j]TJ/MYTW,3'@Q#\[Ao-$jP9^d;9-[W58B<\l;3A<2gD,mP)JkW@7&1Bqb![BuW.lL65_"MPdL+A%PR"bu*bcIGh:P?;RKnY`b&ETF;Ck@t67Y[(9!Co$,6"tr1-gmC^]<:mJ5bYFnKS26?D9i^&Q40J8d+#900&V114mu)JrOC[#Hi^5HK0_SU:D9[kSuq*:nJFW=#M*f,7"lL#LZ'(J;L&mA!r/%P80q@RaT#*>[23['7_)dDS/GC)Fl0QoGkerQ=qZp->=-2'ZICHB[`kG!)2Tq+<1OYL*&`k!r5IQW,s2Hm5SVhAFM19T$aihScELPoO#;kK?,u$E%IA/ofK\2e`Q:-*$R8dpMVjC.]#Hb!BeoT4>lN6X]D/o[Kln+C'U]Y'=ctE^LW,*;^)KC)1KY(269b_>"1^N!.L9g0d!/37`3%FbXjNU/(]C-IX>nHW,AeOHCqc_k99*IKdGi]8V`=BQ<L\]h2\VZ4V@!L8.BAE9/3G'Y,0&0DLo"$D4F,aW<),+i8&:BmL@7'lZ2L#qm#=ca=T"ApB8W0gY>>fVq,SaKK9dUPR+^jJk6Vr7gO=o%7ELaUGOUpMV>BfE62Ce%2]6RN1.2:[`*-o"7,jYd/QrCEpnV\m-s>=@IUN;),n[O+\GJ%"Qcj),P=ZhoJqLp'Ob+gFc_"k`saVBf7ma@a\o'2+X*HPi&2U,k!CJ4?sj1iKFS3CZk0Kg6br'XHX!8a#Mtl0jaZCU*n,[2o9t7X,*V."kY'<MKR%Q^U"V["<%$\*QB,$jm($^I!,e$ukajJCP8F]rbV9G-g"??`IX)(f;W<$O9)VN2!0V>dbs"!o-Eq-h.k]\I:&V8*E[/lSRB4VHVILiAUNb1"N+Z>!C(h^&"oOnSMih5dZ0,"jXq$V'S4&P!qN0@RjYl,8.3)6:I.9GGbr4E`gq/1a#dcPa;b;;f,mF^6Wa]M%>b\;s-";5EiuXbg7Na#h8.dO1MJO1tIAnM@<eeD#"es>!_6OGCCA"F7)!N*s*jel"`"@n.jHY[HMQnh4fiD`;-k2[><1*=BH@)Sq"8E?3R:'WO0\J3'@:mKg^cZ[3a$anYRU/*t]p.:BWj&Y=_>qmO9;5VU6\?Ua.6S_K#Di\JULL32k']7D9Cli]>=1]Mr;,j^c1Op;6NV[kb$Yp7WcN5iF&r`<>YA1Q+d-1.,hjm$mSqS1<&An<d!lG24N)3[jIJUd)H.]UT&J?c3dZuKipQ^I'D0-R!Y1g]2q!,ePYs=5iW61Or0dY8/`](m&O),=8((s;:1'UShJN0pDf\3i^1$2eAnD1<'Y'YRgMW9bpOB`I+Qfheaur,@ht<`0*[![3f7<rVA7Om*X:l;BaZq^+jk4i^W_'/>174oB@;))S+rF!U`t=X<@3C&\7YVM16q!SS,)?IhmLlZ,_4p_c@[Seq7U3(:-b!ps`<\o>Q!=OgKL;[j_ZL3Ni7_qG7_hE#)Q2?7PdD3p7Zi6BFCo-XJ;G]`eg=$W6%_3-7&[sWYZs:=jA&6UR3Phd84G=g,,c$B#?6gE:sH3k+p]J!legKh;R`ZNY@d%fL:T1hG9O[jb#gVEC(X_S@BkYm%Z)A8ck>W"fLZ<A*4s/bV("Jl4W_T"?8A%$aD%V!Um<C"3A>=/3^((K'AJK%^GYL9+2ELO3Y<"@E8D_KdUKh(XE-h`*g.R<b^hIl%49aW=g>?6BpGla@iO)28eYm,19+B,P=-YYgcn;IF1RS%Pa8OTJLoLHr9#J"4S<Mq[6"YmK?>l20BYVf?!FNDZlL?GD5c9FO?:1Xm9M<3LLjJ8.G'.&n_f2o&=c;ZTh-q+5rX`%cLMSO0uZVo[4GO[Y!ts#=kHT0YM(c!]R,!KU1R=Bdac/A,'9(cqSM#,$M^880L6s!!5_/*+Ws$<84Z8_'@eHqn-<>4V*J3LfH+GJ7*ZUemZ+Y2n$@oQb/sCnoC=],";6j^;eZk61iO$JMi.^5_`asd0U[N*OP=GVBtrGK>XTZ:+VFBh'cV!%3l]o,2#ND@.V^caV=ChO$+ILL%F%D*/KHiD"-K^Z][hVYU,UZl=033IF5)nBXrBpn)hpp.bTZfLE5-DM9cKLcR;"2ifS3KBL-KJ2ntFA4)LNUnCY3q<\.<TjO3KNs?&10pC-CNd[6oN$!`,2$dSP9T4CK5iI@[-dW&6[)@11!a.OJ4,>_fec[025Y.8%NLB*tr.,UW#f9mC7GS>49eNhe?_9^((WX7aDH+s]g4H35ki$3TVQT_;;c63ISt"8;,XZ.68*NZr5K=9Npjm0U:ik(J<Lq],MNIB:#N>3DO2A=M?+\W9r>0Yq,#OWk3.Xkd`DN&%bMW/UehUag9_\AD`:2Sh?[g#1<K"JAHtJUX]pS.,\9N**GdP1MBai^,n`doGZt,m<5i-;3eEPI-aH+#*XR=hgZs\rmZok&iu`UP#ZZ<d3nW,O/RpIjk\;,Y%H*>>fX"QX.Z=\:6CFLlYs/1%+c!J5@#?<;=-ok/1W"'=U/2fnBGpilZCb/#stpa'+)JRn829*9s@--DDVL<(;5l'F>'m'C6nP;8U+tb01K3&]NI5JR".H/C>f)GhY2'0N2<VC$<>qIj5qL#h(i?+e?&AcH<*Z4kAS:))aiJ1S1;PI[aH_^VjaTGYiA^n0+;Ld+2nX%_*A'ggQ%-9LH@F2")8$&^L]Jfs&lfCJA#;:Z#"K).`M&K+e9E^l[u-".D?-]E`9>rq%IQJ.2?RoB(NIU%m**d0rIk64].jg[=&8*3!%p7!TTPW#H"_5!Ha^bs`-$7^hpE07R@`4,sm@jE]lhN`"tO]aOnf(.be_((*=4dRX7tm-G)8e)kR3g[&PpiK6T3FFifu]!CAPJsp+(0VsL47gRJ/'>E1+jLXKHH#2O`gDuLW?hU]#TB&5?NZ(FGp')mH)2=N/TJO)31CViYr,]Vh4e'>ni$b&HfFW";=,dgh">O\-T41:(Nc1TeEi.)`\6Pt(,b9VL%".l6Rq3`u#*\645`UFiQ$\fV?kZ3bFUU[p:g&<IFHIPO*I%I.=(DS&%Dks#Pjs;IY`tppmK%iAdY1V\[scIa^D]r?UTq&_L;Bl+GtqE&J_Y\CFks%LJsrQm6(gU<[C4lCn6P\@!@Ae9D]T6!&e0L(,b"=#7"SC&`MmY^J`iAVQuX_ti[.CJqB(u]>#Bu(UbLhM1MjnC*SB,dGM$q5QT"=u'mEC=E(#PJ]!$P2F)j2o9@KJr]AZS[6VpBOW-?C=8eWURdOCPmGXgM1CN::8$:Y:e=Hs4i%'V.=LDhV,BLX-Whb-4sTVd6jIN,t;hYc@D?.3IK"X<^/<F43:K!Bhl+rg8>hfk?VK<D4=V7SI8qs,CJC`\-o@UHtY6kY#P-9$Y4,nV@>.&4TOho+p=^TH^HPMgX(s)7Z^_#rLnHS$q1KS/^&H3`tk6/C.H)8:bt(<.Ldg_]>gB8q$4;"I+\TGg7)gq;bgGRu#8f!8$bIUNS[3F/mtDd]?*3;6je;,3M$[Y(05d@*a*K5;qi1\T4SRMIF:o#:4<lM$M1V4^DiM4'c"lU'Gnl[/R.EP`^kBQhE7,&9QN$s125479\A?nO.!0Mi$3A<oX#:oS\E=<K94#`D)p(Y7M@Ajj24J6sck/aj#cXAK,4#gnUiomtW::EfNg&kZP8-GkuaO4kf)rXZh"q6n*:H^oEi>$JmC5bT`A7eiN<^ULZ&fIUm*gjl:d]uQ#dFZULVX*.X8?.bV`2XW,:A*?'Xi8\<V@lDT^#Ipk#VUIquWnTG]@;,eP>oGqG(8q?qBNl@8$9%,,6lBBt)Jj3t+oCXTRc/poj_20s"=.iO6l<_b1<_<i:r<]6^6)pL2$Y:WL6%16Y^.R9S_Veo'[b3RT,ZQ%#oKT8Z\lT+$:tfKdibHj+j*6Bc1/Y<%*flUeo@t"XZ5Nf^C:AZ9e:7%L4G)C+h,D3i3O]E?fp6UCLFVs3a>m&BcCPLr+&ce&i@TI%d0$X_W&-eKg[!BZZfl9C'YrDTUAiKG&TekJf#c/K'I(3Uc)<]-)h<?3h)-2#$X_;Lc!c&d$r\AP$1_N916#tCF72g;bLoNe$iC21RsksCd@b5&R6RnT@PdVNYd]&)3HbE#171u&B(ZJW&DG.*&X4A;-<pN<.MKeRjdbU.Mr?uE,Z$;,DKtKH6CjSL>7%t$l_^fP85"]jRI3O`7='>&HP?LdR\V"Qo0mPnWc!\dY8VPKct:_7;F5:[KC?A8;p5WO<fnlBTY-q)NQ627>?*A\e[eYEMcFLU"q$O=^@LBeke*%gT#$iTf1KKC)kuJPAOk61.Yi-UJ,/%)Lg;oORU40>D!j6*5372/0D<c!ug1h;]$Ar!Og+tI*U%?Y9Z1?:4V(3A5O<RLLIE,20MNKVB4JgT4oa]KFY7dL^=g;pD`o`8XKg22pe<]1t6t2gGEZf3l]N\\fO4mB0%JFY90uXdnQKH+Z25!K-rZO$9!Hk*gZ#R(mO-&fh`VamGjYn8OsJ&-KHi*8-`3c@V$u$7OEp#,/G6Ob)F1GWX5F+_</NddgaL<2='RrMY2f4H5\0kbA=\9M[%?=NVcHc5<fbI$Zl1qg[<&@o7?[YG$$b0UEXSL'#,U3(:uSelL)!U.YR]GI8n$Kai^X7H5dAa6V]4'.GO<?P9^DGJoX>FD";sU[1*Hu-P"(r#g$$>riAQG@\utTj2-Je.]@%P:Dpd7>!fTI$-1ndVTNQ`OX4f,6R3#:G7;0<6>6umA$JMDB5.gcBO9c%G2W-u`%rFD:cJ/1"0q&Ye9]$I4t&OMWsu9YM8Pg:DoN!6\MOS4"H[$p&QI0$p]4;6bJqR"QmJp0:+&[Hkas']cB$/?ksRor6]dXoP`t1k<&hA$A!UuG7][fS@q%=RF1Q!/Wag_/06Ar&!I.cWjAal-1;ZOk7[kAQUP/Un(-)\ZVT?8RHV.]Phhm2kg85;?^:c<,D,a7&Mc7%P/fNGo_Oj[`:O)ctJL@N^LBUC9F<1]*-F"-,=<A,Y8f(nb"n>F+8Bj\a-t58+=Q!l0#`(/b6j(_EX[mbsb@4>,)OcK#L)h*3KIK21>(kHO91$lg6QecAV3P;OJfnKQ91OuKAiZ=-V@9aG%bhPY+i^)72Ond&JIH)+%"Q=7:6S4@$)CHAOHU86mNREYRk-5h#Rl?-+<r-W..J"jga*d_=72'4r73tE^]XbV#)TU[D6[P-V'_qDUhW;rLbgPlgHqXYZrCk+Rr"P8MNsL%P>*I$=`''gAMkcA9bPE;H,+l>4<-+Mj,GLog)^A%Yk7,/%KTLs%-K<Z,RP_mP6h:a+Tc0a=8KY;Ba"A"Nb<jUr(V=AiB)RF"MY"je4deZC>e>L@.'jP1r4u][`k?Y!(4,$#m^*b8%VkRlRP:COsYc]-&G,h8qpJ:"`..Ijiq#;/#K2G??YHU6VZpPFAUB96EPVAWYBXN/6[cP;XXFTC129hs*"f`0FWL4^dpPS6b,$#$.8gp;;VAm!7\Me2f=9t=16nenfKe5?%0`6lZ>%mn]K$JBj"?5N=%+:k4e:*iDN,Z7$*'\M>6QKNshuLNq_!IfeAcZLG_3D\tm4@?Y%^5ljndmqTFI?#Il_FHfA9^XWC+]9BcIPL\k'k#n>$dUJTNDOKH)QG[S7p+l'3@c372*<<4j,DE6-tAt&R"1N#;a-$KA^5=[,q'-(6,hr=63g<WcIFj:IS*./F'N+LKcZ*o:lP%q.Y=!M,+9;>e8@k^&igU@eb0T=>-)DfDCDV-mC1#SCpDZbAG7!pX*qaMM:?H+GF$\ml+=jqtc6*Om(&]u8&99sK)5_4eSA`8Iu@WhX`L`#Oj0(RlC/dQ;^\8;5i4G'[H(bf=!A26Li8d'0&_4hY'6#oiQ<%C9A6kq0cW_dqX(#BN!`:j/Y1-[5"hU.t<Ud^A2E0C0^.N[donI*0;bmRF-k6d%U)>P/)\Qn&[?kDW(dLch&ll]h,_'_b^</F01U>m80+G0gJ@cFVDZ8Of_849Kr!A&AeZ.T1ASa^h^EKul2Pd=8%E5BV<M1F#`@+?U$$Q?;p%#YBZZ9&ER\>@<+EE,>f2FO#7XTW@Hb[;?E@,\mqg,ER`j@orJ_Ee@:*JXY2$YWp5i5C_;"C_bP'@,?=og$q_P@A",CN^"!'E%Up@HB^4iGUe2YXfT:IKuSg.eX^-/m,S/)/0PnYhs`MH%ou</:1bV-m*^GJ3\r$r"NCn]q]BC?ioBC+[+lYMpL]`U6e(`[k*54lW,=X>:)G*XSIf"9RU7^N9>pno$?1j_PP6l`'ciU7puM3TillcmgY^M4JpeT<^K-.4m2J]f5Tf%#9LVE670V)C1,fdKQ3!);IWuq5<<GOKCF.185W)fha#K0dF7=Yqpc.u$K@(QEpf<PR'8p_p\`![c2(+$rBpXX5FI%=@5o<@-+kKs.FjJTW:h30,ctj)Y7"^&o"3(nlgVV5S1sT%1L.0-*-,,3N`*A!Y$bn+N9#s49&gjqJVTZZ$3Mq;Je27#JC0b/\?Lge6-0:&9R,8@Bn>t)+:X`ESM;GqNFbS7"#]kFIPq#c+Qn/;\PKE&oq@$Q9,%du_[dIB.GbZu62G8ZKHOV`DMF%/TnW%:,lgmL]_$.b%>k8QVt]JLY2f6>Sq.)$73mtPCh1Pc@nLH,9i09G-0jp7[0g]9.A?O?0.l36H!<m<R&Lr]1X>,LQOLbW1rbA=0u7*!73%8:Af?8R0f0e&:Z1@:k^rj\+G'n2em^7'RN&ZQHpSMXoWTE`#BCk7g[t_8Efg#65)>&Gp"\O^1<bJH&/0,sq%r)M.%q_<6'AEiT'+B`:[_=I%[,N$+&WA8Q47UReWL=j4\/+5)PVds5J>ac?YIH%eDJ#2h,R=_8*$R)9fcm"MRu-Lq/lG1:M=dnfnXS)F[Y)J+G'(c\>)<.W-T#+Qm='%1F:H]Vinf.)]3T+?.8,$)+d(9(]]/><G2SFBF'8XNP\2aI8CnQC`)FH9me78+WdNT!MhZ,E4Clc`)3%8\3SJM9*WLsKlM[^,mMaiVcY,]Wan&>jTE."o+pnN'nh6\l=^9M[PpPj/E9o"Af[h+-B-O08!Kb9NL0hQBL7Og(`86gE?NBa4XGQn!87d%J;4uY`1[(27gIk4AOHE,"\qsg>`A,=($L5WeUe).OFWK+&kKWbTIWtr&G`ujdr$hS%\ajCl42cMO^YcuW>\;OSiuP84M/uOU`'Ch!Sml[p(/BUDJrf'"GdP:DFL4"g7F#`ma;,+h[E)&6KcOuo@BQ$?u,3dK:f[+El0!D(>(HS)H+LF&8"T<`\hp=_@?2lVC2$Yeg<S^1kCf_2s>CVA=k'1+?qR_Mm7eDGKJQ6U`H3:BOY(S8;kiZ3$5!DY=/P&*j[L)#:cXm[B,N&Z53dD4sbcT%C1keGPh'/2Kpe?!6A).?pPfG-_=^>KKoZ1&EF76mFL#.,c_^"\Z/9We!t5N(#rSdMjC(*F`$GV,3,t15FXH3!&-g7L1JFu0K<LW-<csL3(f@E/!Q/!8.c1sM$,s!6XU,,f[nL./nu1(Td^J)(LI*MigAg`(8[]2#hk/,&09^R=25q_coM(Doc>-iZ1(0;q4_hY798Ua4#ie*S;s<nHseDW,ZQY3M6pS.iYXUpN#'5P/`;#i;qA_$rHP)=0R8@(ObNo(@%.gB\V2nm*"bBIAs8&-bfl9-2+/sfZDJhnZ*Ts%\^`Nu@bJ*sBh"5lc*dG"TGj<q6X/\EdgUIU[.6A*LX9B.<X;)W"jjgOf[0U>49=IBqVVirgE-F^=@OQ8BE4kHJ;CuWlM;T9OG]>gOV:9-d*?qWMQXm2o=GE2Vc[mK`X0?U)5faq$h]ZI;HSB?YLXn"*s`0\"Om<*lCac%on1$HdZhlFLWkg9)p05,S)CeqRJ9Bh5l!)a$ptM*O3brDm*E\TYl1?2ZJ`h?&kN<1o?JCb:V&.ZNJ(kW+_`c#F&&r0I@FW/g6sW#r&ddd%!I!_rpHTTp-\2KKXg-hPM$$WJG=XJ^bXMJ(QS(n1bZ6]6/1\7D=VXs<(!pc`2u^h#A3g^M4X&KQJgM3*5ICGdcRS,q\1B%E9TJbk,,Re258q`N='kBjm\]SF>TS:.Kbpk$*#6q^nOJU3TP!=-T1/0_%!e;lNY5b"[@lVfZ;M"5['sd,BUKZaMYVg):]iE\46[K\MD+fW\7t92Oi7%LASL'C[elm9#nEV2G^cV55Se7iA"$/"2_L4VF1LBcA)fGScnP2N^Nq?h1R+7jc,t=ZP0plOiD&*E+[p;)"G()+f0/>kSiMb?,D0S6g6p]B+r\/f#^2c`['3K-GtLF+`LWdW#`_lf?AO1jhG]Im<kT<:*XaPH5q^7@8Jj?Hl*HN\erKD,%oEh'8;2!U=44gXF%:0C"#c>bXqfOqnBHVA#tW(ihK)s-$I;EV]\JT:/\&@9['5_)@/I_!9rCKT1,fp4qN2D:fG%UoVa:X@^.`sV*&4o#7EjH>kR]0Ws`Y3S?;lM7?1/Y>t^)o/+X&PJ!sTsWpS*A2s5)9%UINFG>+#:;*d2W'51p"JD@D<(!.ANVE"-;RM#`h.7:)'CX7b#%nA*@e^o_:=?pMPK6].hEk)Z4QodlCh@:D#9Q_X`8A<dqQstauRAZS1[?,/D[.&Aaf$=c5>B9e:T'-_")Ju=ZE+o)-rPP@$dX\$C<DYD$2g2Rk<82m`jVJ1PMj0t'k$/WaD@!8S(0DAs#kjR*1:=16)0$+OX0f9e2\7KPZIr;Cs'mi>Y8Ub,rpR1Cl.MbNMo:@"SFg[dqi'G]a>%>U+:1=F,'et>;@h:D%rR7Rr@CjhLuF4T0c:aZZJQ,q.XJ"'1pSgMM5XGQel7VB"gu:3HY(KYNeU3J_<7lNk_&kU+.40Y4q0^u/),R[4?'<!Z0f>S&FRtBC%NQ[[s8YWQ,Xm\,2,TLq)Poh)=;@u.+1d)%HHiGn+f6V8=YlRVCH0YK90Yq6(&7gmT6d>KOGE/G+&A:V_$=6NZMYjSr*jAq]@<gE"7O71O8H+)fE<g+mSf9%=LNmdZXSqXh(%N&85$6m%kUk-Dt6i4$pu-p[B3U'-`olC0RW#dJ7C%*)e!Y&igXu%1r6fa6!:VFOL9nX3j2abV1FG5e("+748V,\hQJ.O$[djdk"$\aZho4h9T9ZS@6JV(q(O?h2^1QmQ5<u]hhu>`.aom&O4>Pd)]f4Vo"CE*4>6!jl.+!bNh_:<!tCJ4MnauM/m<0&d:e-SsW$R@[!Z7$Ns(clG!*e$9K;cG7lZhcl59lmP'q/I(i&Nd->!mJC/aYD.Pn(lEPF;`"T1A22>$!!>T#I++]fAM.G@#?u#aP]5p=&+<h*#`aH`(K,jFJak@NN<l<US_;SpA`t9/%J'n)j[J?Tfq+.#f+EI3r//oI<h0Q*nQ]*'TRmt3/:HS1acsaC*1s1@Vk,K.cQ?bbGcknU33]2`7Uk12QSj:p<ho=]0]eP*Q9-SgM^m(6s+uFpEq=Nk""M0?nh-.U7icpj3ljk@*0SCQ;.G1Mp@V1-Rfkpe`6P>M,8-+Yu<a*^teC(("8HqLXP>IYV8SDZ<&YCu$s*X5'<R:p-&1<EMJ3WRBVTiG@B*JJ:Q^0EIbCd"ZYLp:2+5_i]r#t&\1.XrHqhT#qL+\^R?10a^k31\)jf+Af@>m1(8)!W!m3Qn`%`35H"1:bG&*HE\K\<)(*$qZ-'ZJ1eF@N#G#&HYk'>2;cJ]=DpMO+""'6KR5:)&%??\[U]kp[*2@MZ@NE06*dSE47_Y^SsO0Y>o0R'@8K)f7L)3uYkj/c@_5@Vjt;(.:'J0bJsPJun30U@OT',!e'*iHGT(TrgJ+]=>E0D2(*?ki8e)1C2p[RI$dZ1S#9s$1LT=UKF!Qpu]VVWO])<'-&,T'e3uBph.LmpH1@sRO`]85u-^tOV*ruK&-hC"B=N\1g'u!MLh`@TICkGau1jD#T>YV?2.nIVJ2#.(?39`&DiRC2^8M"[9<Z1\X9[*#[o&M=:T>U#Xf@P8<d&]3/c&jnAP"O^+'&NQML'nmk!FdAtZ$RPEO"#^i_F_K3Qo)%1H`K4UR[_nC2:lDcbIk`EGR`*,aEqPT/8.3>bFT9rZ9;C6CI]*!"\$U00<e1c]%)@+bl9;g#@D`mZ>%5up=j=-HpT]WU8N,3iJcO'Zt,Y(n>L8t)lF'h2'!dUNX+X'6NW@NBaXkH1i/T%UG<8]eT#:(K-?>aU3<E'];RnZ&O&R>fV?4dRrYV[#'EH]VfZOH2lhB(]B6)&4![ZUPkEJ"<YZAccFmM:Vr0N=]mJb)AnQ;duRA@SDMaE+5mcedTLg%bb"nUaC)eL:+ot(+"j*Yn]/T2;/Nb""`uAg-]M(i6^jhPVn-Z64pgg)[P)93$'j\_[.-ZEm.6sG72WSgO-6iS1S9A9\cGq#0/*'\0*1%CF&Q'%Z>-W(lMO"0LCaf&S_OCNX.72AK&5h&J"c'8Cis)5a+ND)A<^JN3IZ+*1G*>%;;/k)b:flLoJ)i*"[W3BHm-EhcMKS]nkEPXYbs6=L\sOB[X+5JIEKPK+ZHre073*(l">)^nCj%-B'&9W4;I_)[=np,'uj`Bepla1e&B3\+ac^H*j4LYt#@!(lAWPb6:\cL7OTq!.T@5nPM"24>m'hgf[(?6Qi?dRRV-4Os#o3TY(&l.WHI+]@4E?q%#^m[/FUVO'hHr0&.r\gE7`HGaL6]r:Ba=D!(*P"5pA!7%dAlOG>!G8G<N[&Kd6.6lPedk[Y9H%+%^%CB<'/X;GYID2I3Q%LaOlA(m1MD#2P>%Tu9C,EXlc&I@>"a/HLDFr1XH+WT8&1g8u2go']%X-dh0DS8AH+s8RI^7:]g5#@FM^@@Y%j8c8mhR@"9mLLS2L*3VR&J?Y5Ui*a(H&\>ji6(N<IOAZ=A_;rB(\FZQ6gOt-*#3s^@Z!^Yf7Ioq+iNbJVk8'D>3l6hP"0F[U*sg_cgR\4_eD6u\B[IoTi+3MGR'AeFYK)r/H-s[dOc.glYa>6I(Of8V(Eh0W@^L/*OeLs<@O*"VH8/1nuAjtL)e^%cP.IFJ(+(rlgjjl-n1iU7[Z"lECd`sGqVe-O+B[:Ah9`1#db#h4:R4U&oB>NS])$S-@VZm38G1'TPKY#.G=k@T8!BTr:"ho%)gE)Ek.Ocn"]?br\qa(8YEV;7O\X2.h,5di<!Pe6=aN(e2h8P#BgM<^W<58d0i3X3CHQi)@"sh36MRLa5f#l=82#_9Njf#L\=n\7%NIK^BPCKQmSKRH!2DIC=UKR]fE89f9`%02iBskn[E+f`C>HN@G*0h\QWE<qK,\=R_%AQGKV#NgJC`]GB\A]$;``$0JUp,@@S!Dc+8^>oe[W)9Y-KbJrg%M8fGZ&<rsKf8=IBG`iuZ]+i!a4T*^TpRB^9mE$CXA#Mt"tpAb4,3?ii;.d,8YZ7]kQ8;nZ,@##u'M[)XA"L&cB"lcO"jZj*5J5m%:$J65JMAe;ZXXG/9_JDk&1_BjV;\XDD$ZiiirP2&[TX#&S_hTZsJ!Bk^'/82^63ucd2kefRF:PgOeuLWe6ZA/cM'8^sC@U<O&Q_bC&,HP\+KnK7/e(V/JNHfA?.f_KI/9iiJN]mOM4mlGEl:cf/Oi8<9rs=/XK4-kM?Y4nO9uj*4<IhI1OR8#`s!D!UjtoMf2@HYAT3VDU9*"i8kD+I8k4$AcJC-T=_,%[':K.p.1qq_:b]CpE,H(R$3UJOJ\\l<\Yt6[G`X=OLkWRer_@]olq.FC`(^CiN"-gNJRY#m6Kg>[gLSqd+,FpJ)l1=S7=P/m^1r`9!XmeE00At!o_S7k;rrHd,&g7dO\K)^Yp"7_@;%WQ!Q6j^A7;5*H)GD'+l9*5]#VTu+c7lA0[O6eBdRmW<eEZr'o^BsX@THB8.,c.&s[uh@@$LERGG#HBXFC][cch-^Te8^e!>ohI3eX`j]srlQFY-Wj"jq=UI384nSWiADdfNr-J<8fm(V\>.)G`1Z=1o;f+-VE?M'fW4u!@I*#GZdlbmh';tHnYUAJFg9,gQFVK)'n@UI)H&ME<iT?ha$KK"ns&0NMlo:3Yhm0?Rc=q:l\LV4fs#MRIk^3$cNTs@B%3o$OYgQSYs=dLHo4SroDe?;i0+7O\HUVB!4*L0gZ.ks'PWU]cXkAstSq6!N.jk#Wfg`q4fA`b*iUbhc)Dd%)b4K#(CSF7.i/$O4Al9k3U=u7qG4#]7gJbNFoYGjhVV9Vq$E-:;gi)Q<c9?=5?WH,0X^NY%ioNO%m,W4361Gu?_a'I3:eA@AIQYM*ej5*`MoM6ZTS<J(7H%Ff)-8!s3hl6@p6M_]g#rWlf/Mm*Ik\jWFFITnS/I.Zr<DDdP:QXL?A8=m0WSSLHp%CX<?'QUEHU\4;e;%YZbVU#JhDt=in5GG(2@m<]]XR3.Z"o%4:7`k@>jNI7m8aIn8jsp`OS.-PW,c6^)g<jg1f9[\UDTdqZV+DK>hFg0K,`m3'MlA_/u>]hpm1T-f-H1'Oe,f,N#Y"i1NFV+;th,\:mWkZT$[JucCDLi:-.tk1;;'AEID/%&9lZ:>qGW7P0o@tFO6_hb)]l3/G]Oc>uC!ZE+)#BQuX2_Njts^YKV:T,/A,'30V$p*HM(dP<02i8j'V&kX\BgX5(+ee`8&A4D+:PE["9efN73L,Ur+)'D61"\"`?1\pZ<I:,VC*V3XHhk_Ym'*,=8EXud$-+X34MnI`K#A8:qFAIJsb93C%mWA4u:G&llpD^:[(i&QP7X.VN'5geoGR6%3PJt4^'[_jO)YLg`QkBWh[[#r7+P/M\jS3r="8_Di37(ctT`%KrkV]1cD500/H%V]"""AiPon(Nb#$-p^T`Jk$<$+.eT-W45:X_<7Ggm2enMp"pP5;!1$kr/CG'0>Hk]sOWrLrcMYbab7.Lr,R6U);8e/8&FJ3"SltmSqtR<8$2A(S7r!N__$$jr<(G]^rt@<Rorpgj1]f8J(4ammc/].GNpi`U-NY`t*=O?KEAKa+j[]Z.^jH=\`Un'X3f;)q5RaLj'MC]%t-PH/,^`[GTd-R%E,.M)Al0\/K&jV?`8i#^<C,\uZI+MB#;'-bt6d]<Z>\G.]j'C!Pd=6#-j*)WHp`]9O"F`dZaHRCX67=a=*_WHp3"%jP=6,qg*tc?Y"2Us$P*A.<QQECTd[R-+@V^sbncjsM7<d!1$Skn_S4Q"<\;iAHSF0-sA-K7G\6_V15m#e:q-,XV<(\]DWcfi^1?-m!(*YTp,$R=O,fP&62b<@uZ1h9$^iUO1p;V0Wqf^;80V@DR'lLCW(/MnFs)W*0P(J<<[bd\XpmR@LPK^+i#2'9+m*!AGD,26K+7<6\>b0EDM?_;9(7dh/nIE(QKS*-qkSZl%4e,RFX1'#:fha%(n$D1-dsMbE.!s$)oTS<'1@BK`9QA>)qdRi,Kl]88BAX%S:e%N_BKT69=\.`uY:EUNb4pnj$2fNj3F:nf9Mq@7_(_^5JN`"+_eVrr)57Ma%N#5UJ>*kHinbBZ3f]VQ&k-92A+IpN%-=_ketZA8eSm62Q?PXf/kNmUi)jURE#glU'E*[M=r6Aa[2S;46dEQ7>0DlYg$)qa$T4=bcW485H,$q#jOn)9X@Rnf<LC@/uD`+pQNaZ,K4!QCPqXE"Q]o'+>S7f(Xd#c4.-cM1hnioa:nc1VX#*[pC^,8hQ9<QYH"LFa;&7YLH&RTk&Hldl<4d`u9pI`5(03s0_lfXm5n_<(k?#D9d3Bp5GN\a1R%.A2*MGBH?ed8<W8dmqu!>iN,L[MBF7ZERM;E]3?#SZ(I6%F'p1acU,JoXPFmb8(3"pJZVT=Tn`VTjW6%l*f;M47V@q8\Y.`lIusA>Q2Q@UYL<'PYn=`,)kbMlD(S:E"hI9/.=+!5A[ghl^.+eZ^\a'k$R,E2W$N`HTp>VKka-N>cKNh#TiISJ>0lIBsrse=cCTD_cgT=0[Tp7;O@prm]K=@Fks?@>W1Y[F*-0*c%qT-@:<pOPV>PR,"sO\8cbBb(KNnVO*3/])a"4h6KO^V=D*08%#lfC_8JE*mu<"<2.:b`]Z+@u2QPuiD+.?<!#27RdKC-0%$D%B%"uEM+tns'b8d_5-E>/9TagqMpl?$kQ;U;,?1$g<Lj@Tj:'?c`Y*A>0P\[H"7tR4A]X)dE]'m6nR7c^ccVB$S=.\kbenM+Ga*$oEl8.,&3EH8=P%'GnQU@`uRcuHjV)";Tf'Y\Em6upA0H_$<0r%#Obebona<FG(.gdUM5\)XgMD7(5?t(Q51'?X?J&-l,n<+?HTA+?u%o(]@"Kh2dPhfn.4J68;</;sWIV/#e!cCS`OfJdGRFKuXDf2`,AsCN\$I+-$rsH)Kc1"u*[>$f>`7AKfR@DKpLt+uU3=2Z=2_e#f`6,D")(TSUgE?h7<9I3UN&)7]JZ[A(=*.$cX02ZGQ^r3LS`b3-aS;)k.Q#\5!sUU2A29%.!>+(0*q$Suk.<9XhRd&*OO$rO2E/pb9QCS'q'^']`nMDpA;R2"elq<<.hip,18BTgX_=II/D'Oe=N_!C+M!@k&,2MClJhtE5'k$,?9NQd8:r5=gSmAZhIaJ#I7mGtJUgE+0m5N<kV+Ce\XX^:AZ&Mt@8f[%ZmN*nc(cYK@$*uTdME*EL,?1S-/=[k,0[L[FiEJ1l`TQW=%%>u3\L\(ME@t"VeUK7GEX>KBa(oj9=)jSS?ldnX1@T,")YL=ALafOesJj6QaN2-gMudaFK%SWguQgM::/diCtfCRZrg"+E**O,D`,"/1q$9!'5!b(/@?%+o.V6j2TGiq[/nr:!+^.!KFKi/Q\DY\[5_EM1.'HdK,E#Y!6!ebK^]0Q<(+Ys0WU?NVQ<Er,:&tug`oOt?qDKbeuEji6a]"AhW)+0?ZdNn9ju(,6p@F(!0BbpmmH*Q3+_<h-[AsKaEB:mNC6/3MFJd(Z32@JRhDB'<+LQq.^,2amEm(!EZX7]quK/%f57<7DXmXLVNG5M';.lM9aIq&2;9I8%qqAl-'o9ui>ksEoaO32KEZs"ZB\s`Q>2Yf<V&.sQe/>BQU>5-PtZs;*M@%dnsbI:b`YX6=+J.%Lk??*#E()c==EN$^K].uPAaf<dg/&;o0C`g-[@0Z/KiL"-=)!;hX*_iq:RA(%E]$B=Z<?.Z!&Yp'Nir=Ut]TA;bK^k'U#1Y`2$<]Ue1eMBV:t7cmX)DE-e!m5Fh4<e'`G$'0j(8"8-JDrat2nHuMWt)Kp"-OJ+IjfY2@s/ck9GU.+RCf>)&12O!!-Af7/k!o]kJSg&_0GId+pR]e#]Lk_Z*MBSF,a1$M7TMFDNEs:TOLfi4A:$2M3'PqIXO(JKEjOs-6hr=0bF*3^Gn%?oRk+:3-a;mNc]C/U(E?S0d'SA.l'SS:<9,:PCM,7jk0D#ijH@`TUmk2fuO:TIHb"@<D$P:0/i2K+A1sY=C_?E6K9.1XqbW#t7WaJC4d/pc!K0.Eq)#_Sh[LOskj$hO42062&2hA2Lir+%BLEcemE\rBq#\8ZD%?g"Qi0L^>G0\i#%3uUd*%P0GOu@)5Wd9Fp.%:KZ#tc1LBGj>LEF*m;Vdq+d-n=8*/O9T7nBF"EbX%u($63?;7nP?COQ=JsQ.Vbr$o]^K2kaWQ15J87H"XC8<9t?]1BBLd\\@#L<#(-/'8RXlm>p(3YL)rn:7;k3U^/]9erJKDWrE)>f]aRo_$ng93lCZE!bG=Oe%Aif=D#?;?pnBjDO3nVlM#N(DRao<&$ZO3B][.A72kJb\!CMrTs30*JsBG7:A!1I*P+qq+cd-tU[=)]#TFt=(p5G2HD?W9*JnRN(cJkQUDrTObqN^FLFe_lN"m9tc;$aeg-b92pa24T9TJ4Zj@0Hl^foo@n3%$`@q0lXQ=7V,)hG!fK"<+X'#f%LaD`+>Qn`C^<GI+FFTuA40Sge=[YGIPf:cIGfiOABk@Th4l!1ma;8KN"1+d&#ECt7f[90BU9W:Ga+A6+Z=aiH<IkhKD^I>L%$WGP4km:e-V$@n,&*HMRAlLjGq@I#,*rc\T_'EkVLU;[>0o25<_ZD]Q#L6q:Euj)WR.:o.^q"Klk1b1'2!Y5VBd0/$>-[V#3YWFJ6%D6.Q>2c+)h;6L+fhDL&(Bb-G/J=">_/Q?I9\&Pn.3Pn!bm4_p13qQ.)n[J`RIR)fe,-t6_sl]m9i)hrFp9#R<RV^F>*;R*Z`fJHC?'DC/BO.IYCsp,\l$LdH#'24GojZKCVe3`&c?.etDp$m4g:IVjNnj3?Kg8*bU=jg?hkHQUb(33l5i$LrMf?UH,rkRr"4m'<TG6:oE&K@`QYX_p(o$/+:Gr8hi4HXf]"-2nPGV9Sb<Hh%[?<@#K,cfQTDeD?(^4ih^aFH9)\#6O5Y5&BmoT>SaqhZuF(r,!CQTMFG,n=eL1<FH\DTOMON"[[H+[M;tXjU)R\J3Q>Yr#1S@-X#dLnCIRQF>"6W9#H4St2JVKkMk3jc=S<@h8H.k19V[s5RA@Y(,e3$tJ12Fq_\c&X#CaW+_CidP-;:D/V+4K@a'6@(Q;enF@CBiN6A-P_]k!Ki*P%Z!_Jp-?M#oC4kQ:fl$40QVBpih'+5NTl;kr\Qn0&pHJ`"$(e_ENPGnN\hbYquG)<+WTd$"L;/DO/!:^@B)d7mS^3ooP2oAT'f`q>EI(T1Zq,13bEh82j1PT/_qXqrF;+ZPA`<YTSA8N=rpB51n_#;&,O@g(3b;HupmJ55VBPVo@8f&TB+3WkDb(gqq\`0$GK1(YTr_$4-'iD!MhD'IaPAF/_l-t4-oE&'=.<n\B"[3U\Z/_i%=+f>GiFH\EfX#-jE.l-5/G@i`s$Q4Fsgc@,L:j3[eCjF5OiSBT]PV1@pZ7d=^>gJnBg?j58e4[@'B;Wcb;tlVgTp%Ej/K6qU4JtTX_jAMeVW"4!*#S_^$EHft-V@'WG')U,=dpUei,*6r`O_JYq*lVh,30q?;3*%16t8mD0W\Aa2A[RQ@E+CK.Von0_7jBtD$"kOj;1PS.!+"!bo74a<@0:!C6FaL>c<h%<0h5/9,loJ=?_S*I;p8YJ]gZ#;e=Od6&rH=#!cQQ`M'+18gH731#nudA5qZ@iR5$'Or3f-f3TtLktEg:,>Z#o*hM<LrLPh.WJs8JhfN@a4:pLN)hut"U7Tm41+`2^EZ92j".]aYmH8/`AeCmoAh9l;g;U$j)W$-1"1%>ScL1G]%o*1c!gW'=Dh+WEB+dnihi@<\dR<ib0r2sJBX2#)*#/[2c!fQ]X'EX+T![:hX*h&rRUP$WTgjg,$&=gV<#uFL>\f%i_?5EX?'rhb<?OS0b>_rjL=4#l%;\s3.MR\9Lo1@c'@:-#CWA/H2Z]]Y$O%oX.%=:cPZMqK5d"Q0%MDtID6e6L7&7?Tf#IdCV%)l<$C6'_,Uh7/C2@6h'&sfL:tg&3i;82Fq-)VNQJR^(0p.(R:D8NC(>"l)1iks[Ad*iC79q\ulI+/MMO"W?;ZhXW14\%IfFk"oP)eg"UYluf>pbNZj&p!4lcn.NRX-g;dEU)j7tI"Qd[P8F+u$mP9H[d$&H\+jS3fFR[_8RZ9"6>%(*]$oQlRYn>1OIbPo:#%GGWJ(7[`JQN/$`EZ2uYb%KeXFOg@J:X]Ql1'ri7YB[9h:N,AcX_[QhZ&fV&OM+BQSViNG-6\D?Xc$nr>9AM\h%`u6AJ-/;>/WaZ6^c=h<<T_ZPM3Ljs?%IXa=t/5o:-0)UY2Or#.,;%^7Qk&Q2Io'q(i"^,\F0NBYQi80E"Fr27P@Wm,"ra(O<'n-0uEAf"d9.l6K)tsN'bC"/ek//\4hqKPArmA+I[mu)23XOZ#_,QNepf9qS$I((I*0[TYoA>BnoQ=RZ0c>(FSV8*>cc'G<Vd*oA5.NKL-dg@4$Mdi;cZGQV@Ip2I6DnA(qk:ZQT$7=a^'#h0(HJ2*c)r!sW)#1<K:tr/Z[J*L_/o78_r1k9:<KHU$?;rjsVFS_3#4%McOnLIYbk5pj:6OOt9$!;77<R<I6e"/^BaOMY*S`o:HDm<[7DabRT9&j;Bd)pm%2.`/G;1\NN2g(n:Bo=VYZEL`[?c#)n&O'bT0G7f/"0N61N9k96S#]`b76c-<]C(CSt'/8HdcQgI7]mU>jgu9=m:6TXPVk%QZ,E*"+F21?H\d7]V-AHG8kVeoa;>bnPT_^".[j6m5bCmr.6b"urG)%l3*q8pF0a`c56;M5mliK96n]<q4BcYiW.9&t2@#P:d`#g5a]SBo4W#c"205>nP)+@/c3(4O=5@;(j%b"NGS/@]8"%4:d?*^A(>pG60gF5gT8ID2E)6AeJO\iqSY<6sjQ9Z?bKP#A"0N1BBP#)StB_DEWAe1)IS)9dC4Rk$CS@"jClP([fe7V\i#Bhe6&gTdp%R3.r9<YVrNe2OD*1>F1OWeSArB$;R=KHd]Le3AAh*!Y9%>LghPJQ5Oi0c]K3;*QPW)+N@D%QE1Oq=q5Tjm43`4ZQtMaL$59OV15Hk\q8A5F+.&#Z2RWG?NT$Pa6N@>5V\N'A7n6K-m+_X?A5YW;f6&7.rs!f3itX6)qU&B(gY0+oK"@T]#@Y/s##8op)k9)KI*Rr.G-&JZmSRB-^h'J7!T)NiMU]IT^E'2Slu6jW5%M8@ok":B@s63lE*Yi\8<?N!J&$'68'F\?*WkLB3P+[_pql`)'Cc_ge)7;r;42;="%KD]2u!X'YD*0YGM_q"95p6[XBAtL1$G3;5KmF:of^5'!7N'2'%kiF(U_J6$;QZ5$>>#r'hH0:35RZAK$Y"a_a<2=Yk0ki1I(aV##;'^\.-7MoFaOgn,dhX&s(f&P1CF+!."JGh<A))Ej[UNbK^TO":]V5j0`hmOXZb9m3!ni.%[c;]33d.^Jo6"62,(DKg,c$k=?&*X1du]!r%1%?O,5@U[TMgHk]hcQ*>FP`SB\5(rh.(CsQ,6n+iR3,"/7QUeSn;*J.YXLR$kEinY_q-.U-sGI=t8lp9H4@ne0OBa4(io,Uk21PIFAOlYY?k:5^'OJG[baM#GJ5B2T&?17PT<N'SQg,[Q6/f,=(:q9bfEL=t#0"M)J<rZn`5L5T#U3mDI,<*=Pt0(/%ZSf_Y>]:uEMc!t@H@J^"`EUF:Z;U/`L-<6Zc:g+sY#M&(Y7!eIq>fN3:157ZOGj6?=/p@S('k\lZjP@:ebV2qOBm/gcWR8HAP%Fmk0(7ZkD<<[Hr4#t^_ifrdtK@CCR5#;hA69rF#&qfh?lj)qPHpSL`HPE0&5^A`ISV&8^qI+JqeXA0dj*4Ij3$)CknbB[KRrd;-7TF]k<KsiVEO5>lcC\qo>J(h4_7H+-2^Xb=#PI$6GdlsR>dX7<-:U<RG&nm40npSN2blXW#gj)*jJ.YOQF'Hl+"D$(2TMa2a8)-[U:<-%lT!ip8/b!&L2V-;k8%49RrgX<mLIuS)H<lU;M#O]NNFX6,@u@g?ADjX66B^HlXKZ-?HI0+.'+;,hOJtIG_1'Wh#lj.]6ai4kT=rt:Nu8(UFk/CKL`q'fcnkW%YQ\R\dBSo4@7,?!Pr,-&pa3`431q=*QImGh*BMi/c'J`9bM:Zf#'n+>3&-W)4ChuUe1i(@g.3=f\G.6KHcC7oj);uZ%e&G;t)_kBf7/'\RgR%D2+]$5[/4)<Y'\,M=:,4n(q-`rBF$Z3s.>qGnEbGmk#%4VrT5X3X;ldifOuRnpWms@XOe3?,-Kn#1/SX655Vk2V8IoCKb87aMe1do/p-W_^9oU-"Ybq+dgZE@4m.G-?<#j"!o]*_D0JHUjfkIOS&cu#!/L_'YpI[bl8-^A]*-YQ^A[T:Z`0c]@?<>8&7ReaqUNQ66ns\,=><0&8\5`s#]K&mQ`mr'5(^1$&=SQP`dFu+cqNeW?=cE&O%XO4"hc\GUNJm1nLi>/ulU"D=HFT'D\P2cL'/&`K!o$10,>RFrH3;qG2!`J2mb6*J4-$;uE_Pi#X;'r7F%PYLN@B#Cp4N=m$<3e-cupYGHdBd>-)N0`I)-'CUA55dJA4BQ9g"J8Sur2=mhc^WaaC)=`Y+3\b2:/28n#,6916_[))E#Wr&V9]On$G#CMCAns6n!C[Q;M>\fXC^VWL+kR+GpPg7mW[N6l>#7gW.8=iVWXMRa)CU8P`%WmqJVmmcdL%.o'Dj(V@1;,^S."F4+!3"^Dp\d@LX"sB*IE3.;b[At<2\_FcuNYTjiGl=Ul^`_PE81)6REB]#F:?L>t"P+09^shfCAq<=5El$+o-7tjmuN>d([4.B#Y,18X>TSdRt3[?`pCD2V[W"cRt=]\TCOtR_>hP)Y5iPJQ2uL*Cq%MR@"MG$2MK9@@h1)5^r'',&F(/NEWNH=P2,-(:B&H75JDM>"uH@9oU[$%5R_1_Q6)IMGYWc!?sc2bNV@tc_QMu9a35sk`e86JEZHc(a\Fi$IF2%MW#kKEsi7?JsT:JS44-gnd1J1q1qEr#36WBo9qpi.m+FK0[A>%9'4d#;++B"@D7pCAqHpU,%M&]8Jkm)P8RtaUJ:euR;8t2`)0[,Y-RAiX#2Z^dqttOAW7/TCNTe[TkQ?jeMWUC[+NK2e66W>>FIE`;RO\R:fn#DE"#2;<A9)6,/[j)%7Z/1?eHeO=<*KN&G5qUO/Xis.dqn_'+Gj-9ndY-1(Mb`$>dUJ-FnVY8EkD?M:FH0b]%B@$8d>&n@H6.TGm@/`Ph[*X/Tsd.K/A.-0U:i2&iOqm%.][YRJ6Yh04P%Q2A3V)4=-lYS]Or;3_V&2c3aepAH2ae$1rGB!H.D2]\7j&V=a_CRkBMWq89<)VrXTGi&LmXh0<bf9jLaJYYii`?thB9KFAW!q7@:D*VJ\;d4ttr4mEiT(ihQ4&dfJJ[Fa\0USZt-KK3Oh[TZXQ2Q""r9J^.U*.>n$pJ?G/8;*2KkMhF$*XtoCAkbK2JAr^f?\jl\[es*SJ3&h^k?n%m]mWQmLS(:#]Vh\`>u:U25@?hY@kalGR*?,_C2(^rQVn^^:-rb<Ygq.AdcNF_26X)o"X52\j%.)V4ApQ!j)\d.G<(b&\KtALnZZ"6'.LbR5@\$_7+YTpIk(ZVEel3fAL'5&E73*bd$_]mPd$m/^"![m?eRrZY!s2elM6&j2i,mI#/]JAk5/_J+N>_h<k4As'PO#QiCFlf`1^GL\sC7I/g8EI\6MIs5Wa$qu=S4s763)p4(]oq]l)Inc-f409?)smf12es,[0Jr`=U0s"F?njo/WKs7^I-IPtU0#_E<Y#o!&rIs:MmL?l>5%0'_>C06Ss_#3JINmt_>;%^*+]5JeAS-GQ9b]4`>/oCPpHt?"NTo\GC)8YfPX4YT^G7frm;R?m1Y+lSY@"AP!r^>]`OHN1Rl!''5J?A40$Qmh>o%^G6`LHmud;4q4HVV6#.A8f@Y_<%$TaA.qV"d$c*en=(QpqKmB2*/8&QQi4#$kt'jCqf;2VT3kQ.i%&n:&^L^,At\/BIrPljP&V<7ChBqa+ZS-2V76)[M\a5lrhG?)@ji_]P2L@(m(gM#Y[/Je_[/ep6#"R&KB3@GcLU^X9KfL`.?;>La_dFaB7kHr=%Om%`O<2h_UWfQ4amWc\7ueB0\X#c^Di(ta>mC,chD,@g<J2%pB<.Y;@[L2t&5bZV:X!4E,[(c?nFnAIQ;f+:fp,^^jKa?h"1&GDSH,Bgtr5U9i3C]E->Xe;<b!MYd"#"5JT>A=eUMTrN^hZ3NWg\RmNrcb!I"kTrhe*]6c]rmjp<g@tt5hi&@@_5XF=2YO!mhuE+AiAfKmc*>`<7jRChf#oS]g;[OBR:_:Qcp&9RWO<L1U3th?'6*n"//FCN>c?@=j5CLioB"bUP?)tg_sK,eLhYRL2qABc6G'<2FaVfbLmm9^&<4kB6tF=Y`Cd$6A(+Ai>clQ*+8rE+pA5i$6:;I(",("FM5Kti7okQ"J>'K-*V&X,"=PKg]V:^6^TXA)Ve*rX5E.4isp?PNZZ$MagcSU7:p?=;IKZHF@6'G-rPr@#XL4DYTYP!6jdo#\-IPCMA2acN[+R%;nki0!<7;<5ED1X`"4XO*CsOdl-&Sk!5>K8O"R;3!*Xj0qIOG&5d/6PjV.TqPQR0`J[E$V<,6FP$Ad%]ai7?IW7HL#P;*tf^QnEO5Q$T>ebcXfa<q&&/:ZdmHpXR2`dAW")K[ZGrll1;&,WINm/Ja8RK$c(MdmU0=BhuUkP-a!VLQ<P^D*1:b-_RJj3[OlW=djoAEW`Rs2$Ru.0!j"k8\\`41_kZNJNN-B[LmIVP?l3(ZBW!aQo=#aP#%Ql0AJ%e?lZ^!FM?>hfg?<<)L<J*dbJBh=f_`qA3N+?fD%R?bgIIT>"\'Dom>jL5JEpr[2[9B]8\a)mY_dUE0&Bn4*3%gs36G'"HohHeg8;U+hQZ&H"_=%"Cde6i2Ki#QMcuO\QT93P\61!!
+# ===>END WOOF<===
--- a/wscript	Thu Jul 19 13:17:35 2007 +0200
+++ b/wscript	Fri Sep 28 11:59:46 2007 +0100
@@ -1,13 +1,14 @@
 ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
-import os
 import sys
 import shlex
 import shutil
+import types
+import optparse
+import os.path
 
 import Params
 import Object
 import pproc as subprocess
-import optparse
 
 Params.g_autoconfig = 1
 
@@ -19,9 +20,9 @@
 srcdir = '.'
 blddir = 'build'
 
-def dist_hook(srcdir, blddir):
-    shutil.rmtree("doc/html")
-    shutil.rmtree("doc/latex")
+def dist_hook():
+    shutil.rmtree("doc/html", True)
+    shutil.rmtree("doc/latex", True)
 
 def set_options(opt):
 
@@ -36,7 +37,7 @@
 
     opt.add_option('-d', '--debug-level',
                    action='callback',
-                   type=str, dest='debug_level', default='debug',
+                   type="string", dest='debug_level', default='ultradebug',
                    help=('Specify the debug level, does nothing if CFLAGS is set'
                          ' in the environment. [Allowed Values: debug, optimized].'
                          ' WARNING: this option only has effect '
@@ -65,8 +66,14 @@
                    dest='doxygen')
 
     opt.add_option('--run',
-                   help=('Run a locally built program'),
+                   help=('Run a locally built program; argument can be a program name,'
+                         ' or a command starting with the program name.'),
                    type="string", default='', dest='run')
+    opt.add_option('--command-template',
+                   help=('Template of the command used to run the program given by --run;'
+                         ' It should be a shell command string containing %s inside,'
+                         ' which will be replaced by the actual program.'),
+                   type="string", default=None, dest='command_template')
 
     opt.add_option('--shell',
                    help=('Run a shell with an environment suitably modified to run locally built programs'),
@@ -78,8 +85,7 @@
 
 
 def configure(conf):
-    if not conf.check_tool('compiler_cxx'):
-        Params.fatal("No suitable compiler found")
+    conf.check_tool('compiler_cxx')
 
     # create the second environment, set the variant and set its name
     variant_env = conf.env.copy()
@@ -89,6 +95,8 @@
     else:
         variant_name = debug_level
 
+    variant_env['INCLUDEDIR'] = os.path.join(variant_env['PREFIX'], 'include')
+
     if Params.g_options.enable_gcov:
         variant_name += '-gcov'
         variant_env.append_value('CCFLAGS', '-fprofile-arcs')
@@ -105,12 +113,30 @@
 
     variant_env.append_value('CXXDEFINES', 'RUN_SELF_TESTS')
     
-    if os.path.basename(conf.env['CXX']).startswith("g++"):
-        variant_env.append_value('CXXFLAGS', ['-Wall', '-Werror'])
+    if (os.path.basename(conf.env['CXX']).startswith("g++")
+        and 'CXXFLAGS' not in os.environ):
+        variant_env.append_value('CXXFLAGS', ['-Werror'])
 
     if 'debug' in Params.g_options.debug_level.lower():
         variant_env.append_value('CXXDEFINES', 'NS3_DEBUG_ENABLE')
         variant_env.append_value('CXXDEFINES', 'NS3_ASSERT_ENABLE')
+        variant_env.append_value('CXXDEFINES', 'NS3_LOG_ENABLE')
+
+    ## In optimized builds we still want debugging symbols, e.g. for
+    ## profiling, and at least partially usable stack traces.
+    if ('optimized' in Params.g_options.debug_level.lower() 
+        and 'CXXFLAGS' not in os.environ):
+        for flag in variant_env['CXXFLAGS_DEBUG']:
+            ## this probably doesn't work for MSVC
+            if flag.startswith('-g'):
+                variant_env.append_value('CXXFLAGS', flag)
+
+    ## in optimized builds, replace -O2 with -O3
+    if 'optimized' in Params.g_options.debug_level.lower():
+        lst = variant_env['CXXFLAGS']
+        for i, flag in enumerate(lst):
+            if flag == '-O2':
+                lst[i] = '-O3'
 
     if sys.platform == 'win32':
         if os.path.basename(conf.env['CXX']).startswith("g++"):
@@ -119,22 +145,43 @@
     conf.sub_config('src')
 
 
+def create_ns3_program(bld, name, dependencies=('simulator',)):
+    program = bld.create_obj('cpp', 'program')
+    program.name = name
+    program.target = program.name
+    program.uselib_local = 'ns3'
+    return program
+
+
 def build(bld):
+    print "Entering directory `%s/build'" % Params.g_build.m_curdirnode.abspath()
+    Params.g_cwd_launch = Params.g_build.m_curdirnode.abspath()
+
+    bld.create_ns3_program = types.MethodType(create_ns3_program, bld)
+
     variant_name = bld.env_of_name('default')['NS3_ACTIVE_VARIANT']
     variant_env = bld.env_of_name(variant_name)
     bld.m_allenvs['default'] = variant_env # switch to the active variant
 
-    if Params.g_options.run:
-        run_program(Params.g_options.run)
-        return
-    elif Params.g_options.shell:
+    if Params.g_options.shell:
         run_shell()
-        return
+        raise SystemExit(0)
+
+    if Params.g_options.doxygen:
+        doxygen()
+        raise SystemExit(0)
+
+    check_shell()
 
     # process subfolders from here
     bld.add_subdirs('src')
-    bld.add_subdirs('samples utils examples')
+    bld.add_subdirs('samples utils examples tutorial')
 
+    ## Create a single ns3 library containing all modules
+    lib = bld.create_obj('cpp', 'shlib')
+    lib.name = 'ns3'
+    lib.target = 'ns3'
+    lib.add_objects = list(bld.env_of_name('default')['NS3_MODULES'])
 
 def shutdown():
     #import UnitTest
@@ -151,64 +198,127 @@
     if Params.g_options.lcov_report:
         lcov_report()
 
-    if Params.g_options.doxygen:
-        doxygen()
+    if Params.g_options.run:
+        run_program(Params.g_options.run, Params.g_options.command_template)
+        raise SystemExit(0)
+
+    if Params.g_options.command_template:
+        Params.fatal("Option --command-template requires the option --run to be given")
 
-def _find_program(program_name):
+def _find_program(program_name, env):
+    launch_dir = os.path.abspath(Params.g_cwd_launch)
+    found_programs = []
     for obj in Object.g_allobjs:
+        if obj.m_type != 'program' or not obj.target:
+            continue
+
+        ## filter out programs not in the subtree starting at the launch dir
+        if not (obj.path.abspath().startswith(launch_dir)
+                or obj.path.abspath(env).startswith(launch_dir)):
+            continue
+        
+        found_programs.append(obj.target)
         if obj.target == program_name:
             return obj
-    raise ValueError("progam '%s' not found" % (program_name,))
+    raise ValueError("program '%s' not found; available programs are: %r"
+                     % (program_name, found_programs))
 
-def _run_argv(argv):
+def _run_argv(argv, os_env=None):
     env = Params.g_build.env_of_name('default')
     if sys.platform == 'linux2':
         pathvar = 'LD_LIBRARY_PATH'
-        pathsep = ':'
     elif sys.platform == 'darwin':
         pathvar = 'DYLD_LIBRARY_PATH'
-        pathsep = ':'
     elif sys.platform == 'win32':
         pathvar = 'PATH'
-        pathsep = ';'
     elif sys.platform == 'cygwin':
         pathvar = 'PATH'
-        pathsep = ':'
     else:
         Params.warning(("Don't know how to configure "
                         "dynamic library path for the platform '%s'") % (sys.platform,))
         pathvar = None
-        pathsep = None
 
-    os_env = dict(os.environ)
+    proc_env = dict(os.environ)
+    if os_env is not None:
+        proc_env.update(os_env)
+
     if pathvar is not None:
-        if pathvar in os_env:
-            os_env[pathvar] = pathsep.join([os_env[pathvar]] + list(env['NS3_MODULE_PATH']))
+        if pathvar in proc_env:
+            proc_env[pathvar] = os.pathsep.join(list(env['NS3_MODULE_PATH']) + [proc_env[pathvar]])
         else:
-            os_env[pathvar] = pathsep.join(list(env['NS3_MODULE_PATH']))
+            proc_env[pathvar] = os.pathsep.join(list(env['NS3_MODULE_PATH']))
 
-    retval = subprocess.Popen(argv, env=os_env).wait()
+    retval = subprocess.Popen(argv, env=proc_env).wait()
     if retval:
-        raise SystemExit(retval)
+        Params.fatal("Command %s exited with code %i" % (argv, retval))
 
 
-def run_program(program_string):
+def run_program(program_string, command_template=None):
+    """
+    if command_template is not None, then program_string == program
+    name and argv is given by command_template with %s replaced by the
+    full path to the program.  Else, program_string is interpreted as
+    a shell command with first name being the program name.
+    """
     env = Params.g_build.env_of_name('default')
-    argv = shlex.split(program_string)
-    program_name = argv[0]
+
+    if command_template is None:
+        argv = shlex.split(program_string)
+        program_name = argv[0]
+
+        try:
+            program_obj = _find_program(program_name, env)
+        except ValueError, ex:
+            Params.fatal(str(ex))
+
+        try:
+            program_node, = program_obj.m_linktask.m_outputs
+        except AttributeError:
+            Params.fatal("%s does not appear to be a program" % (program_name,))
+
+        execvec = [program_node.abspath(env)] + argv[1:]
 
+    else:
+
+        program_name = program_string
+        try:
+            program_obj = _find_program(program_name, env)
+        except ValueError, ex:
+            Params.fatal(str(ex))
+        try:
+            program_node, = program_obj.m_linktask.m_outputs
+        except AttributeError:
+            Params.fatal("%s does not appear to be a program" % (program_name,))
+
+        execvec = shlex.split(command_template % (program_node.abspath(env),))
+
+
+    former_cwd = os.getcwd()
+    os.chdir(Params.g_cwd_launch)
     try:
-        program_obj = _find_program(program_name)
-    except ValueError:
-        Params.fatal("progam '%s' not found" % (program_name,))
+        retval = _run_argv(execvec)
+    finally:
+        os.chdir(former_cwd)
+
+    return retval
 
-    try:
-        program_node, = program_obj.m_linktask.m_outputs
-    except AttributeError:
-        Params.fatal("%s does not appear to be a program" % (program_name,))
-
-    execvec = [program_node.abspath(env)] + argv[1:]
-    return _run_argv(execvec)
+def check_shell():
+    if 'NS3_MODULE_PATH' not in os.environ:
+        return
+    env = Params.g_build.env_of_name('default')
+    correct_modpath = os.pathsep.join(env['NS3_MODULE_PATH'])
+    found_modpath = os.environ['NS3_MODULE_PATH']
+    if found_modpath != correct_modpath:
+        msg = ("Detected shell (waf --shell) with incorrect configuration\n"
+               "=========================================================\n"
+               "Possible reasons for this problem:\n"
+               "  1. You switched to another ns-3 tree from inside this shell\n"
+               "  2. You switched ns-3 debug level (waf configure --debug)\n"
+               "  3. You modified the list of built ns-3 modules\n"
+               "You should correct this situation before running any program.  Possible solutions:\n"
+               "  1. Exit this shell, and start a new one\n"
+               "  2. Run a new nested shell")
+        Params.fatal(msg)
 
 
 def run_shell():
@@ -216,7 +326,9 @@
         shell = os.environ.get("COMSPEC", "cmd.exe")
     else:
         shell = os.environ.get("SHELL", "/bin/sh")
-    _run_argv([shell])
+
+    env = Params.g_build.env_of_name('default')
+    _run_argv([shell], {'NS3_MODULE_PATH': os.pathsep.join(env['NS3_MODULE_PATH'])})
 
 
 def doxygen():