trace consistency changes
authorCraig Dowell <craigdo@ee.washington.edu>
Sat, 28 Feb 2009 16:25:24 -0800
changeset 4263 fec2f830d015
parent 4244 7c98934dcccd
child 4264 9d2e96c4e6e4
trace consistency changes
examples/wifi-wired-bridging.cc
src/devices/csma/csma-net-device.cc
src/devices/csma/csma-net-device.h
src/devices/emu/emu-net-device.cc
src/devices/emu/emu-net-device.h
src/devices/point-to-point/point-to-point-channel.h
src/devices/point-to-point/point-to-point-net-device.cc
src/devices/point-to-point/point-to-point-net-device.h
src/devices/wifi/adhoc-wifi-mac.cc
src/devices/wifi/mac-low.cc
src/devices/wifi/nqap-wifi-mac.cc
src/devices/wifi/nqsta-wifi-mac.cc
src/devices/wifi/wifi-mac.cc
src/devices/wifi/wifi-mac.h
src/devices/wifi/wifi-net-device.cc
src/devices/wifi/wifi-net-device.h
src/devices/wifi/wifi-phy.cc
src/devices/wifi/wifi-phy.h
src/devices/wifi/yans-wifi-phy.cc
src/devices/wifi/yans-wifi-phy.h
src/helper/csma-helper.cc
src/helper/csma-helper.h
src/helper/emu-helper.cc
src/helper/emu-helper.h
src/helper/point-to-point-helper.cc
src/helper/point-to-point-helper.h
src/helper/wifi-helper.cc
src/helper/wifi-helper.h
src/helper/yans-wifi-helper.cc
--- a/examples/wifi-wired-bridging.cc	Wed Feb 25 12:27:00 2009 -0500
+++ b/examples/wifi-wired-bridging.cc	Sat Feb 28 16:25:24 2009 -0800
@@ -183,8 +183,11 @@
   apps.Start (Seconds (0.5));
   apps.Stop (Seconds (3.0));
   
-  YansWifiPhyHelper::EnablePcap ("wifi-wired-bridging", staNodes[1].Get (1));
-  YansWifiPhyHelper::EnablePcap ("wifi-wired-bridging", staNodes[0].Get (0));
+  WifiHelper::EnablePcap ("wifi-wired-bridging", staNodes[1].Get (1));
+  WifiHelper::EnablePcap ("wifi-wired-bridging", staNodes[0].Get (0));
+
+  YansWifiPhyHelper::EnablePcap ("wifi-wired-bridging-promisc", staNodes[1].Get (1));
+  YansWifiPhyHelper::EnablePcap ("wifi-wired-bridging-promisc", staNodes[0].Get (0));
   std::ofstream os;
   os.open ("wifi-wired-bridging.mob");
   MobilityHelper::EnableAsciiAll (os);
--- a/src/devices/csma/csma-net-device.cc	Wed Feb 25 12:27:00 2009 -0500
+++ b/src/devices/csma/csma-net-device.cc	Sat Feb 28 16:25:24 2009 -0800
@@ -77,17 +77,65 @@
                    PointerValue (),
                    MakePointerAccessor (&CsmaNetDevice::m_receiveErrorModel),
                    MakePointerChecker<ErrorModel> ())
+
+    //
+    // Transmit queueing discipline for the device which includes its own set
+    // of trace hooks.
+    //
     .AddAttribute ("TxQueue", 
                    "A queue to use as the transmit queue in the device.",
                    PointerValue (),
                    MakePointerAccessor (&CsmaNetDevice::m_queue),
                    MakePointerChecker<Queue> ())
-    .AddTraceSource ("Rx", 
-                     "Trace source indicating reception of packet destined for broadcast, multicast or local address.",
-                     MakeTraceSourceAccessor (&CsmaNetDevice::m_rxTrace))
-    .AddTraceSource ("Drop", 
-                     "Trace source indicating packet discarded due to receiver disabled or error model decision.",
-                     MakeTraceSourceAccessor (&CsmaNetDevice::m_dropTrace))
+
+    //
+    // Trace sources at the "top" of the net device, where packets transition
+    // to/from higher layers.
+    //
+    .AddTraceSource ("MacTx", 
+                     "Trace source indicating a packet has arrived for transmission by this device",
+                     MakeTraceSourceAccessor (&CsmaNetDevice::m_macTxTrace))
+    .AddTraceSource ("MacTxDrop", 
+                     "Trace source indicating a packet has been dropped by the device before transmission",
+                     MakeTraceSourceAccessor (&CsmaNetDevice::m_macTxDropTrace))
+    .AddTraceSource ("MacRx", 
+                     "Trace source indicating a packet has been received by this device and is being forwarded up the stack",
+                     MakeTraceSourceAccessor (&CsmaNetDevice::m_macRxTrace))
+    //
+    // Trace souces at the "bottom" of the net device, where packets transition
+    // to/from the channel.
+    //
+    .AddTraceSource ("PhyTxStart", 
+                     "Trace source indicating a packet has begun transmitting over the channel",
+                     MakeTraceSourceAccessor (&CsmaNetDevice::m_phyTxStartTrace))
+    .AddTraceSource ("PhyTx", 
+                     "Trace source indicating a packet has been completely transmitted over the channel",
+                     MakeTraceSourceAccessor (&CsmaNetDevice::m_phyTxTrace))
+    .AddTraceSource ("PhyTxDrop", 
+                     "Trace source indicating a packet has been dropped by the device during transmission",
+                     MakeTraceSourceAccessor (&CsmaNetDevice::m_phyTxDropTrace))
+    .AddTraceSource ("PhyRxStart", 
+                     "Trace source indicating a packet has begun being received by the device",
+                     MakeTraceSourceAccessor (&CsmaNetDevice::m_phyRxStartTrace))
+    .AddTraceSource ("PhyRx", 
+                     "Trace source indicating a packet has been completely received by the device",
+                     MakeTraceSourceAccessor (&CsmaNetDevice::m_phyRxTrace))
+    .AddTraceSource ("PhyRxDrop", 
+                     "Trace source indicating a packet has been dropped by the device during reception",
+                     MakeTraceSourceAccessor (&CsmaNetDevice::m_phyRxDropTrace))
+    .AddTraceSource ("PhyTxBackoff", 
+                     "Trace source indicating a packet has been delayed by the CSMA backoff process",
+                     MakeTraceSourceAccessor (&CsmaNetDevice::m_phyTxBackoffTrace))
+
+    //
+    // Trace sources designed to simulate a packet sniffer facility (tcpdump). 
+    //
+    .AddTraceSource ("Sniffer", 
+                     "Trace source simulating a non-promiscuous packet sniffer attached to the device",
+                     MakeTraceSourceAccessor (&CsmaNetDevice::m_snifferTrace))
+    .AddTraceSource ("PromiscSniffer", 
+                     "Trace source simulating a promiscuous packet sniffer attached to the device",
+                     MakeTraceSourceAccessor (&CsmaNetDevice::m_promiscSnifferTrace))
     ;
   return tid;
 }
@@ -102,11 +150,15 @@
   m_channel = 0; 
 
   // 
-  // We would like to let the attribute system take care of initializing the packet encapsulation stuff, but we also don't want to
-  // get caught up in initialization order changes.  So we'll get the three problem variables into a consistent state here before the
-  // attribute calls, and then depend on the semantics of the setters to preserve a consistent state.  This really doesn't have to be
-  // the same set of values as the initial values set by the attributes, but it does have to be a consistent set.  That is, you can
-  // just change the ddfault encapsulation mode above without having to change it here.  We keep it the same for GP.
+  // We would like to let the attribute system take care of initializing the 
+  // packet encapsulation stuff, but we also don't want to get caught up in
+  // initialization order changes.  So we'll get the three problem variables
+  // into a consistent state here before the attribute calls, and then depend
+  // on the semantics of the setters to preserve a consistent state.  This 
+  // really doesn't have to be the same set of values as the initial values 
+  // set by the attributes, but it does have to be a consistent set.  That is,
+  // you can just change the default encapsulation mode above without having 
+  // to change it here.
   //
   m_encapMode = DIX;
   m_frameSize = DEFAULT_FRAME_SIZE;
@@ -332,7 +384,8 @@
     case DIX:
       NS_LOG_LOGIC ("Encapsulating packet as DIX (type interpretation)");
       //
-      // This corresponds to the type interpretation of the lengthType field as in the old Ethernet Blue Book.
+      // This corresponds to the type interpretation of the lengthType field as
+      // in the old Ethernet Blue Book.
       //
       lengthType = protocolNumber;
       break;
@@ -407,38 +460,47 @@
 }
 
   void
-CsmaNetDevice::TransmitStart ()
+CsmaNetDevice::TransmitStart (void)
 {
   NS_LOG_FUNCTION_NOARGS ();
 
   //
   // This function is called to start the process of transmitting a packet.  We 
-  // expect that a Ptr to the packet to be transmitted has been placed in 
-  // m_currentPkt.
+  // expect that the packet to transmit will be found in m_currentPkt.
+  //
+  NS_ASSERT_MSG (m_currentPkt != 0, "CsmaNetDevice::TransmitStart(): m_currentPkt not set");
 
-  NS_LOG_LOGIC ("m_currentPkt=" << m_currentPkt);
-  NS_LOG_LOGIC ("UID is " << m_currentPkt->GetUid ());
+  NS_LOG_LOGIC ("m_currentPkt = " << m_currentPkt);
+  NS_LOG_LOGIC ("UID = " << m_currentPkt->GetUid ());
 
   //
-  // 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.
+  // Only transmit if the send side of net device is enabled
+  //
+  if (IsSendEnabled () == false)
+    {
+      m_phyTxDropTrace (m_currentPkt);
+      m_currentPkt = 0;
+      return;
+    }
+
+  //
+  // Somebody has called here telling us to start transmitting a packet.  They 
+  // can only do this if the state machine is in the READY or BACKOFF state.
+  // Specifically, if we are ready to start transmitting, we cannot already
+  // be transmitting (i.e., BUSY)
   //
   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
+  // Now we have to sense the state of the medium and either start transmitting
+  // if it is idle, or backoff our transmission if someone else is on the wire.
   //
-  if (IsSendEnabled () == false)
-    {
-      return;
-    }
-
   if (m_channel->GetState () != IDLE)
     {
       //
-      // The channel is busy -- backoff and rechedule TransmitStart ()
+      // The channel is busy -- backoff and rechedule TransmitStart() unless
+      // we have exhausted all of our retries.
       //
       m_txMachineState = BACKOFF;
 
@@ -451,6 +513,8 @@
         } 
       else 
         {
+          m_phyTxBackoffTrace (m_currentPkt);
+
           m_backoff.IncrNumRetries ();
           Time backoffTime = m_backoff.GetBackoffTime ();
 
@@ -464,48 +528,47 @@
       //
       // The channel is free, transmit the 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) == false)
         {
-          NS_LOG_WARN ("Channel transmit start did not work at " << tEvent.GetSeconds () << "sec");
+          NS_LOG_WARN ("Channel TransmitStart returns an error");
+          m_phyTxDropTrace (m_currentPkt);
+          m_currentPkt = 0;
           m_txMachineState = READY;
         } 
       else 
         {
           //
-          // Transmission succeeded, reset the backoff time parameters.
+          // Transmission succeeded, reset the backoff time parameters and
+          // schedule a transmit complete event.
           //
           m_backoff.ResetBackoffTime ();
+          m_txMachineState = BUSY;
+          m_phyTxStartTrace (m_currentPkt);
+
+          Time tEvent = Seconds (m_bps.CalculateTxTime (m_currentPkt->GetSize ()));
+          NS_LOG_LOGIC ("Schedule TransmitCompleteEvent in " << tEvent.GetSeconds () << "sec");
+          Simulator::Schedule (tEvent, &CsmaNetDevice::TransmitCompleteEvent, this);
         }
     }
 }
 
-
   void
 CsmaNetDevice::TransmitAbort (void)
 {
   NS_LOG_FUNCTION_NOARGS ();
 
   //
-  // When we started transmitting the current packet, it was placed in 
-  // m_currentPkt.  So we had better find one there.
+  // When we started the process of transmitting the current packet, it was 
+  // placed in m_currentPkt.  So we had better find one there.
   //
   NS_ASSERT_MSG (m_currentPkt != 0, "CsmaNetDevice::TransmitAbort(): m_currentPkt zero");
   NS_LOG_LOGIC ("m_currentPkt=" << m_currentPkt);
   NS_LOG_LOGIC ("Pkt UID is " << m_currentPkt->GetUid () << ")");
 
-  //
-  // Hit the drop trace source.
-  //
-  // XXX Should there be a separate transmit drop trace?
-  //
-  m_dropTrace (m_currentPkt);
+  m_phyTxDropTrace (m_currentPkt);
+  m_currentPkt = 0;
+
+  NS_ASSERT_MSG (m_txMachineState == BACKOFF, "Must be in BACKOFF state to abort.  Tx state is: " << m_txMachineState);
 
   // 
   // We're done with that one, so reset the backoff algorithm and ready the
@@ -527,6 +590,8 @@
     {
       m_currentPkt = m_queue->Dequeue ();
       NS_ASSERT_MSG (m_currentPkt != 0, "CsmaNetDevice::TransmitAbort(): IsEmpty false but no Packet on queue?");
+      m_snifferTrace (m_currentPkt);
+      m_promiscSnifferTrace (m_currentPkt);
       TransmitStart ();
     }
 }
@@ -555,6 +620,8 @@
   NS_LOG_LOGIC ("Pkt UID is " << m_currentPkt->GetUid () << ")");
 
   m_channel->TransmitEnd (); 
+  m_phyTxTrace (m_currentPkt);
+  m_currentPkt = 0;
 
   NS_LOG_LOGIC ("Schedule TransmitReadyEvent in " << m_tInterframeGap.GetSeconds () << "sec");
 
@@ -575,12 +642,10 @@
   m_txMachineState = READY;
 
   //
-  // When we started transmitting the current packet, it was placed in 
-  // m_currentPkt.  So we had better find one there.
+  // We expect that the packet we had been transmitting was cleared when the 
+  // TransmitCompleteEvent() was executed.
   //
-  NS_ASSERT_MSG (m_currentPkt != 0, "CsmaNetDevice::TransmitCompleteEvent(): m_currentPkt zero");
-  NS_LOG_LOGIC ("m_currentPkt=" << m_currentPkt);
-  NS_LOG_LOGIC ("Pkt UID is " << m_currentPkt->GetUid () << ")");
+  NS_ASSERT_MSG (m_currentPkt == 0, "CsmaNetDevice::TransmitReadyEvent(): m_currentPkt nonzero");
 
   //
   // Get the next packet from the queue for transmitting
@@ -593,6 +658,8 @@
     {
       m_currentPkt = m_queue->Dequeue ();
       NS_ASSERT_MSG (m_currentPkt != 0, "CsmaNetDevice::TransmitReadyEvent(): IsEmpty false but no Packet on queue?");
+      m_snifferTrace (m_currentPkt);
+      m_promiscSnifferTrace (m_currentPkt);
       TransmitStart ();
     }
 }
@@ -658,21 +725,26 @@
   multicast6Node.CopyFrom(mac);
 
   //
-  // We never forward up packets that we sent. Real devices don't do this since
-  // their receivers are disabled during send, so we don't. Drop the packet
-  // silently (no tracing) since it would really never get here in a real device.
+  // We never forward up packets that we sent.  Real devices don't do this since
+  // their receivers are disabled during send, so we don't.
   // 
   if (senderDevice == this)
     {
       return;
     }
 
+  //
+  // Hit the trace hook.  This trace will fire on all packets received from the
+  // channel except those originated by this device.
+  //
+  m_phyRxTrace (packet);
+
   // 
   // Only receive if the send side of net device is enabled
   //
   if (IsReceiveEnabled () == false)
     {
-      m_dropTrace (packet);
+      m_phyRxDropTrace (packet);
       return;
     }
 
@@ -695,7 +767,7 @@
   if (m_receiveErrorModel && m_receiveErrorModel->IsCorrupt (packet) )
     {
       NS_LOG_LOGIC ("Dropping pkt due to error model ");
-      m_dropTrace (packet);
+      m_phyRxDropTrace (packet);
     }
   else
     {
@@ -717,12 +789,14 @@
           protocol = header.GetLengthType ();
         }
 
+      //
+      // Classify the packet based on its destination.
+      //
       PacketType packetType;
       
       if (header.GetDestination ().IsBroadcast ())
         {
           packetType = PACKET_BROADCAST;
-          m_rxTrace (originalPacket);
         }
       else if (header.GetDestination ().IsMulticast () ||
           header.GetDestination() == multicast6Node ||
@@ -731,25 +805,36 @@
           header.GetDestination() == multicast6AllHosts)
         {
           packetType = PACKET_MULTICAST;          
-          m_rxTrace (originalPacket);
         }
       else if (header.GetDestination () == m_address)
         {
           packetType = PACKET_HOST;
-          m_rxTrace (originalPacket);
         }
       else
         {
           packetType = PACKET_OTHERHOST;
         }
-      
+
+      // 
+      // For all kinds of packetType we receive, we hit the promiscuous sniffer
+      // hook and pass a copy up to the promiscuous callback.  Pass a copy to 
+      // make sure that nobody messes with our packet.
+      //
+      m_promiscSnifferTrace (originalPacket);
       if (!m_promiscRxCallback.IsNull ())
         {
-          m_promiscRxCallback (this, packet, protocol, header.GetSource (), header.GetDestination (), packetType);
+          m_promiscRxCallback (this, packet->Copy (), protocol, header.GetSource (), header.GetDestination (), packetType);
         }
 
+      //
+      // If this packet is not destined for some other host, it must be for us
+      // as either a broadcast, multicast or unicast.  We need to hit the mac
+      // packet received trace hook and forward the packet up the stack.
+      //
       if (packetType != PACKET_OTHERHOST)
         {
+          m_snifferTrace (originalPacket);
+          m_macRxTrace (originalPacket);
           m_rxCallback (this, packet, protocol, header.GetSource ());
         }
     }
@@ -893,7 +978,7 @@
 CsmaNetDevice::SendFrom (Ptr<Packet> packet, const Address& src, const Address& dest, uint16_t protocolNumber)
 {
   NS_LOG_FUNCTION (packet << src << dest << protocolNumber);
-  NS_LOG_LOGIC ("p=" << packet);
+  NS_LOG_LOGIC ("packet =" << packet);
   NS_LOG_LOGIC ("UID is " << packet->GetUid () << ")");
 
   NS_ASSERT (IsLinkUp ());
@@ -903,6 +988,7 @@
   //
   if (IsSendEnabled () == false)
     {
+      m_macTxDropTrace (packet);
       return false;
     }
 
@@ -910,11 +996,15 @@
   Mac48Address source = Mac48Address::ConvertFrom (src);
   AddHeader (packet, source, destination, protocolNumber);
 
+  m_macTxTrace (packet);
+
   //
-  // Place the packet to be sent on the send queue
+  // Place the packet to be sent on the send queue.  Note that the 
+  // queue may fire a drop trace, but we will too.
   //
   if (m_queue->Enqueue(packet) == false)
     {
+      m_macTxDropTrace (packet);
       return false;
     }
 
@@ -925,12 +1015,12 @@
   //
   if (m_txMachineState == READY) 
     {
-      //
-      // The next packet to be transmitted goes in m_currentPkt
-      //
-      m_currentPkt = m_queue->Dequeue ();
-      if (m_currentPkt != 0)
+      if (m_queue->IsEmpty () == false)
         {
+          m_currentPkt = m_queue->Dequeue ();
+          NS_ASSERT_MSG (m_currentPkt != 0, "CsmaNetDevice::SendFrom(): IsEmpty false but no Packet on queue?");
+          m_promiscSnifferTrace (packet);
+          m_snifferTrace (packet);
           TransmitStart ();
         }
     }
--- a/src/devices/csma/csma-net-device.h	Wed Feb 25 12:27:00 2009 -0500
+++ b/src/devices/csma/csma-net-device.h	Sat Feb 28 16:25:24 2009 -0800
@@ -637,25 +637,132 @@
   Ptr<Queue> m_queue;
 
   /**
-   * Error model for receive packet events
+   * Error model for receive packet events.  When active this model will be
+   * used to model transmission errors by marking some of the packets 
+   * received as corrupt.
    */
   Ptr<ErrorModel> m_receiveErrorModel;
 
   /**
-   * The trace source for the packet reception events that the device can
-   * fire.
+   * The trace source fired when packets come into the "top" of the device
+   * at the L3/L2 transition, before being queued for transmission.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_macTxTrace;
+
+  /**
+   * The trace source fired when packets coming into the "top" of the device
+   * at the L3/L2 transition are dropped before being queued for transmission.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_macTxDropTrace;
+
+  /**
+   * The trace source fired for packets successfully received by the device
+   * immediately before being forwarded up to higher layers (at the L2/L3 
+   * transition).
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_macRxTrace;
+
+  /**
+   * The trace source fired when a packet starts the transmission process on
+   * the medium.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_phyTxStartTrace;
+
+  /**
+   * The trace source fired when a packet ends the transmission process on
+   * the medium.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_phyTxTrace;
+
+  /**
+   * The trace source fired when the phy layer drops a packet as it tries
+   * to transmit it.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_phyTxDropTrace;
+
+  /**
+   * The trace source fired when a packet ends the reception process from
+   * the medium.
    *
    * \see class CallBackTraceSource
    */
-  TracedCallback<Ptr<const Packet> > m_rxTrace;
+  TracedCallback<Ptr<const Packet> > m_phyRxTrace;
+
+  /**
+   * The trace source fired when a packet ends the reception process from
+   * the medium.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_phyRxStartTrace;
 
   /**
-   * The trace source for the packet drop events that the device can
-   * fire.
+   * The trace source fired when the phy layer drops a packet it has received.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_phyRxDropTrace;
+
+  /**
+   * The trace source fired when the phy layer is forced to begin the backoff
+   * process for a packet.  This can happen a number of times as the backoff
+   * sequence is repeated with increasing delays.
    *
    * \see class CallBackTraceSource
    */
-  TracedCallback<Ptr<const Packet> > m_dropTrace;
+  TracedCallback<Ptr<const Packet> > m_phyTxBackoffTrace;
+
+  /**
+   * A trace source that emulates a non-promiscuous protocol sniffer connected 
+   * to the device.  Unlike your average everyday sniffer, this trace source 
+   * will not fire on PACKET_OTHERHOST events.
+   *
+   * On the transmit size, this trace hook will fire after a packet is dequeued
+   * from the device queue for transmission.  In Linux, for example, this would
+   * correspond to the point just before a device hard_start_xmit where 
+   * dev_queue_xmit_nit is called to dispatch the packet to the PF_PACKET 
+   * ETH_P_ALL handlers.
+   *
+   * On the receive side, this trace hook will fire when a packet is received,
+   * just before the receive callback is executed.  In Linux, for example, 
+   * this would correspond to the point at which the packet is dispatched to 
+   * packet sniffers in netif_receive_skb.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_snifferTrace;
+
+  /**
+   * A trace source that emulates a promiscuous mode protocol sniffer connected
+   * to the device.  This trace source fire on packets destined for any host
+   * just like your average everyday packet sniffer.
+   *
+   * On the transmit size, this trace hook will fire after a packet is dequeued
+   * from the device queue for transmission.  In Linux, for example, this would
+   * correspond to the point just before a device hard_start_xmit where 
+   * dev_queue_xmit_nit is called to dispatch the packet to the PF_PACKET 
+   * ETH_P_ALL handlers.
+   *
+   * On the receive side, this trace hook will fire when a packet is received,
+   * just before the receive callback is executed.  In Linux, for example, 
+   * this would correspond to the point at which the packet is dispatched to 
+   * packet sniffers in netif_receive_skb.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_promiscSnifferTrace;
 
   /**
    * The Node to which this device is attached.
@@ -671,6 +778,7 @@
    * The callback used to notify higher layers that a packet has been received.
    */
   NetDevice::ReceiveCallback m_rxCallback;
+
   /**
    * The callback used to notify higher layers that a packet has been received in promiscuous mode.
    */
--- a/src/devices/emu/emu-net-device.cc	Wed Feb 25 12:27:00 2009 -0500
+++ b/src/devices/emu/emu-net-device.cc	Sat Feb 28 16:25:24 2009 -0800
@@ -22,17 +22,18 @@
 #include "ns3/log.h"
 #include "ns3/queue.h"
 #include "ns3/simulator.h"
-#include "ns3/realtime-simulator-impl.h"
-#include "ns3/mac48-address.h"
 #include "ns3/ethernet-header.h"
 #include "ns3/ethernet-trailer.h"
 #include "ns3/llc-snap-header.h"
+#include "ns3/boolean.h"
+#include "ns3/uinteger.h"
+#include "ns3/pointer.h"
+#include "ns3/string.h"
 #include "ns3/trace-source-accessor.h"
-#include "ns3/pointer.h"
 #include "ns3/channel.h"
 #include "ns3/system-thread.h"
-#include "ns3/string.h"
-#include "ns3/boolean.h"
+#include "ns3/realtime-simulator-impl.h"
+#include "ns3/mac48-address.h"
 
 #include <sys/wait.h>
 #include <sys/stat.h>
@@ -82,14 +83,72 @@
                    TimeValue (Seconds (0.)),
                    MakeTimeAccessor (&EmuNetDevice::m_tStop),
                    MakeTimeChecker ())
+
+    //
+    // Transmit queueing discipline for the device which includes its own set
+    // of trace hooks.  Note that this is really going to run "on top of" the 
+    // queueing discipline that will most likely be present in the devices of
+    // the underlying operating system.
+    //
     .AddAttribute ("TxQueue", 
                    "A queue to use as the transmit queue in the device.",
                    PointerValue (),
                    MakePointerAccessor (&EmuNetDevice::m_queue),
                    MakePointerChecker<Queue> ())
-    .AddTraceSource ("Rx", 
-                     "Trace source indicating recvfrom of packet destined for broadcast, multicast or local address.",
-                     MakeTraceSourceAccessor (&EmuNetDevice::m_rxTrace))
+
+    //
+    // Trace sources at the "top" of the net device, where packets transition
+    // to/from higher layers.  These points do not really correspond to the 
+    // MAC layer of the underlying operating system, but exist to provide 
+    // a consitent tracing environment.  These trace hooks should really be
+    // interpreted as the points at which a packet leaves the ns-3 environment
+    // destined for the underlying operating system or vice-versa.
+    //
+    .AddTraceSource ("MacTx", 
+                     "Trace source indicating a packet has arrived for transmission by this device",
+                     MakeTraceSourceAccessor (&EmuNetDevice::m_macTxTrace))
+    .AddTraceSource ("MacTxDrop", 
+                     "Trace source indicating a packet has been dropped by the device before transmission",
+                     MakeTraceSourceAccessor (&EmuNetDevice::m_macTxDropTrace))
+    .AddTraceSource ("MacRx", 
+                     "Trace source indicating a packet has been received by this device and is being forwarded up the stack",
+                     MakeTraceSourceAccessor (&EmuNetDevice::m_macRxTrace))
+    //
+    // In normal ns-3 net devices, these trace souces correspond to the "bottom"
+    // of the net device, where packets transition to/from the channel.  In 
+    // the case of the emu device, there is no physical layer access and so
+    // these are duplicates of the MAC-level hooks.  Intepret these points
+    // also as the points at which a packet leaves the ns-3 environment
+    // destined for the underlying operating system or vice-versa.
+    //
+    .AddTraceSource ("PhyTxStart", 
+                     "Trace source indicating a packet has begun transmitting over the channel",
+                     MakeTraceSourceAccessor (&EmuNetDevice::m_phyTxStartTrace))
+    .AddTraceSource ("PhyTx", 
+                     "Trace source indicating a packet has been completely transmitted over the channel",
+                     MakeTraceSourceAccessor (&EmuNetDevice::m_phyTxTrace))
+    .AddTraceSource ("PhyTxDrop", 
+                     "Trace source indicating a packet has been dropped by the device during transmission",
+                     MakeTraceSourceAccessor (&EmuNetDevice::m_phyTxDropTrace))
+    .AddTraceSource ("PhyRxStart", 
+                     "Trace source indicating a packet has begun being received by the device",
+                     MakeTraceSourceAccessor (&EmuNetDevice::m_phyRxStartTrace))
+    .AddTraceSource ("PhyRx", 
+                     "Trace source indicating a packet has been completely received by the device",
+                     MakeTraceSourceAccessor (&EmuNetDevice::m_phyRxTrace))
+    .AddTraceSource ("PhyRxDrop", 
+                     "Trace source indicating a packet has been dropped by the device during reception",
+                     MakeTraceSourceAccessor (&EmuNetDevice::m_phyRxDropTrace))
+
+    //
+    // Trace sources designed to simulate a packet sniffer facility (tcpdump). 
+    //
+    .AddTraceSource ("Sniffer", 
+                     "Trace source simulating a non-promiscuous packet sniffer attached to the device",
+                     MakeTraceSourceAccessor (&EmuNetDevice::m_snifferTrace))
+    .AddTraceSource ("PromiscSniffer", 
+                     "Trace source simulating a promiscuous packet sniffer attached to the device",
+                     MakeTraceSourceAccessor (&EmuNetDevice::m_promiscSnifferTrace))
     ;
   return tid;
 }
@@ -490,6 +549,19 @@
 {
   NS_LOG_FUNCTION (buf << len);
 
+  /* IPv6 support*/
+  uint8_t mac[6];
+  Mac48Address multicast6AllNodes("33:33:00:00:00:01");
+  Mac48Address multicast6AllRouters("33:33:00:00:00:02");
+  Mac48Address multicast6AllHosts("33:33:00:00:00:03");
+  Mac48Address multicast6Node; /* multicast address addressed to our MAC address */
+
+  /* generate IPv6 multicast ethernet destination that nodes will accept */
+  GetAddress().CopyTo(mac);
+  mac[0]=0x33;
+  mac[1]=0x33;
+  multicast6Node.CopyFrom(mac);
+
   //
   // Create a packet out of the buffer we received and free that buffer.
   //
@@ -504,6 +576,13 @@
   Ptr<Packet> originalPacket = packet->Copy ();
 
   //
+  // Hit the trace hook.  This trace will fire on all packets received from the
+  // OS (promiscuous).  Packets are received instantaneously.
+  //
+  m_phyRxStartTrace (packet);
+  m_phyRxTrace (packet);
+
+  //
   // Checksum the packet
   //
   EthernetTrailer trailer;
@@ -516,43 +595,68 @@
   NS_LOG_LOGIC ("Pkt source is " << header.GetSource ());
   NS_LOG_LOGIC ("Pkt destination is " << header.GetDestination ());
 
-  LlcSnapHeader llc;
-  packet->RemoveHeader (llc);
-  uint16_t protocol = llc.GetType ();
+  uint16_t protocol;
+  
+  //
+  // If the length/type is less than 1500, it corresponds to a length 
+  // interpretation packet.  In this case, it is an 802.3 packet and 
+  // will also have an 802.2 LLC header.  If greater than 1500, we
+  // find the protocol number (Ethernet type) directly.
+  //
+  if (header.GetLengthType () <= 1500)
+    {
+      LlcSnapHeader llc;
+      packet->RemoveHeader (llc);
+      protocol = llc.GetType ();
+    }
+  else
+    {
+      protocol = header.GetLengthType ();
+    }
 
   PacketType packetType;
       
   if (header.GetDestination ().IsBroadcast ())
     {
-      NS_LOG_LOGIC ("Pkt destination is PACKET_BROADCAST");
       packetType = NS3_PACKET_BROADCAST;
     }
-  else if (header.GetDestination ().IsMulticast ())
+  else if (header.GetDestination ().IsMulticast () ||
+           header.GetDestination() == multicast6Node ||
+           header.GetDestination() == multicast6AllNodes ||
+           header.GetDestination() == multicast6AllRouters ||
+           header.GetDestination() == multicast6AllHosts)
     {
-      NS_LOG_LOGIC ("Pkt destination is PACKET_MULTICAST");
-      packetType = NS3_PACKET_MULTICAST;
+      packetType = NS3_PACKET_MULTICAST;          
     }
   else if (header.GetDestination () == m_address)
     {
-      NS_LOG_LOGIC ("Pkt destination is PACKET_HOST");
       packetType = NS3_PACKET_HOST;
     }
   else
     {
-      NS_LOG_LOGIC ("Pkt destination is PACKET_OTHERHOST");
       packetType = NS3_PACKET_OTHERHOST;
     }
 
+  // 
+  // For all kinds of packetType we receive, we hit the promiscuous sniffer
+  // hook and pass a copy up to the promiscuous callback.  Pass a copy to 
+  // make sure that nobody messes with our packet.
+  //
+  m_promiscSnifferTrace (originalPacket);
   if (!m_promiscRxCallback.IsNull ())
     {
-      NS_LOG_LOGIC ("calling m_promiscRxCallback");
       m_promiscRxCallback (this, packet->Copy (), protocol, header.GetSource (), header.GetDestination (), packetType);
     }
 
+  //
+  // If this packet is not destined for some other host, it must be for us
+  // as either a broadcast, multicast or unicast.  We need to hit the mac
+  // packet received trace hook and forward the packet up the stack.
+  //
   if (packetType != NS3_PACKET_OTHERHOST)
     {
-      m_rxTrace (originalPacket);
-      NS_LOG_LOGIC ("calling m_rxCallback");
+      m_snifferTrace (originalPacket);
+      m_macRxTrace (originalPacket);
       m_rxCallback (this, packet, protocol, header.GetSource ());
     }
 }
@@ -632,10 +736,12 @@
 EmuNetDevice::SendFrom (Ptr<Packet> packet, const Address &src, const Address &dest, uint16_t protocolNumber)
 {
   NS_LOG_FUNCTION (packet << src << dest << protocolNumber);
+  NS_LOG_LOGIC ("packet =" << packet);
+  NS_LOG_LOGIC ("UID is " << packet->GetUid () << ")");
 
   if (IsLinkUp () == false)
     {
-      NS_LOG_LOGIC ("Link is down, returning");
+      m_macTxDropTrace (packet);
       return false;
     }
 
@@ -646,34 +752,11 @@
   NS_LOG_LOGIC ("Transmit packet from " << source);
   NS_LOG_LOGIC ("Transmit packet to " << destination);
 
-#if 0
-  {
-    struct ifreq ifr;
-    bzero (&ifr, sizeof(ifr));
-    strncpy ((char *)ifr.ifr_name, m_deviceName.c_str (), IFNAMSIZ);
-
-    NS_LOG_LOGIC ("Getting MAC address");
-    int32_t rc = ioctl (m_sock, SIOCGIFHWADDR, &ifr);
-    if (rc == -1)
-      {
-        NS_FATAL_ERROR ("EmuNetDevice::SendFrom(): Can't get MAC address");
-      }
-
-    std::ostringstream oss;
-    oss << std::hex <<
-      (ifr.ifr_hwaddr.sa_data[0] & 0xff) << ":" <<
-      (ifr.ifr_hwaddr.sa_data[1] & 0xff) << ":" <<
-      (ifr.ifr_hwaddr.sa_data[2] & 0xff) << ":" <<
-      (ifr.ifr_hwaddr.sa_data[3] & 0xff) << ":" <<
-      (ifr.ifr_hwaddr.sa_data[4] & 0xff) << ":" <<
-      (ifr.ifr_hwaddr.sa_data[5] & 0xff) << std::dec;
-
-    NS_LOG_LOGIC ("Fixup source to HW MAC " << oss.str ());
-    source = Mac48Address (oss.str ().c_str ());
-    NS_LOG_LOGIC ("source now " << source);
-  }
-#endif
-
+  //
+  // We've got to pick either DIX (Ethernet) or LLC/SNAP (IEEE 802.3) as a 
+  // packet format.  IEEE 802.3 is slightly more formally correct, so we 
+  // go that route.
+  //
   LlcSnapHeader llc;
   llc.SetType (protocolNumber);
   packet->AddHeader (llc);
@@ -688,11 +771,23 @@
   trailer.CalcFcs (packet);
   packet->AddTrailer (trailer);
 
+  //
+  // there's not much meaning associated with the different layers in this
+  // device, so don't be surprised when they're all stacked together in 
+  // essentially one place.  We do this for trace consistency across devices.
+  //
+  m_macTxTrace (packet);
+
   // 
-  // Enqueue and dequeue the packet to hit the tracing hooks.
+  // Enqueue and dequeue the packet to hit the queue tracing hooks.
   //
   m_queue->Enqueue (packet);
   packet = m_queue->Dequeue ();
+  NS_ASSERT_MSG (packet, "EmuNetDevice::SendFrom(): packet zero from queue");
+
+  m_promiscSnifferTrace (packet);
+  m_snifferTrace (packet);
+
 
   struct sockaddr_ll ll;
   bzero (&ll, sizeof (ll));
@@ -703,10 +798,13 @@
 
   NS_LOG_LOGIC ("calling sendto");
 
+  m_phyTxStartTrace (packet);
+
   int32_t rc;
   rc = sendto (m_sock, packet->PeekData (), packet->GetSize (), 0, reinterpret_cast<struct sockaddr *> (&ll), sizeof (ll));
+  NS_LOG_LOGIC ("sendto returns " << rc);
 
-  NS_LOG_LOGIC ("sendto returns " << rc);
+  m_phyTxTrace (packet);
 
   return rc == -1 ? false : true;
 }
--- a/src/devices/emu/emu-net-device.h	Wed Feb 25 12:27:00 2009 -0500
+++ b/src/devices/emu/emu-net-device.h	Sat Feb 28 16:25:24 2009 -0800
@@ -264,20 +264,116 @@
   Ptr<Queue> m_queue;
 
   /**
-   * The trace source for the packet reception events that the device can
-   * fire.
+   * The trace source fired when packets come into the "top" of the device
+   * at the L3/L2 transition, before being queued for transmission.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_macTxTrace;
+
+  /**
+   * The trace source fired when packets coming into the "top" of the device
+   * at the L3/L2 transition are dropped before being queued for transmission.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_macTxDropTrace;
+
+  /**
+   * The trace source fired for packets successfully received by the device
+   * immediately before being forwarded up to higher layers (at the L2/L3 
+   * transition).
    *
-   * @see class CallBackTraceSource
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_macRxTrace;
+
+  /**
+   * The trace source fired when a packet starts the transmission process on
+   * the medium.
+   *
+   * \see class CallBackTraceSource
    */
-  TracedCallback<Ptr<const Packet> > m_rxTrace;
+  TracedCallback<Ptr<const Packet> > m_phyTxStartTrace;
+
+  /**
+   * The trace source fired when a packet ends the transmission process on
+   * the medium.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_phyTxTrace;
+
+  /**
+   * The trace source fired when the phy layer drops a packet as it tries
+   * to transmit it.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_phyTxDropTrace;
 
   /**
-   * The trace source for the packet drop events that the device can
-   * fire.
+   * The trace source fired when a packet ends the reception process from
+   * the medium.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_phyRxTrace;
+
+  /**
+   * The trace source fired when a packet starts the reception process from
+   * the medium.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_phyRxStartTrace;
+
+  /**
+   * The trace source fired when the phy layer drops a packet it has received.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_phyRxDropTrace;
+
+  /**
+   * A trace source that emulates a non-promiscuous protocol sniffer connected 
+   * to the device.  Unlike your average everyday sniffer, this trace source 
+   * will not fire on PACKET_OTHERHOST events.
    *
-   * @see class CallBackTraceSource
+   * On the transmit size, this trace hook will fire after a packet is dequeued
+   * from the device queue for transmission.  In Linux, for example, this would
+   * correspond to the point just before a device hard_start_xmit where 
+   * dev_queue_xmit_nit is called to dispatch the packet to the PF_PACKET 
+   * ETH_P_ALL handlers.
+   *
+   * On the receive side, this trace hook will fire when a packet is received,
+   * just before the receive callback is executed.  In Linux, for example, 
+   * this would correspond to the point at which the packet is dispatched to 
+   * packet sniffers in netif_receive_skb.
+   *
+   * \see class CallBackTraceSource
    */
-  TracedCallback<Ptr<const Packet> > m_dropTrace;
+  TracedCallback<Ptr<const Packet> > m_snifferTrace;
+
+  /**
+   * A trace source that emulates a promiscuous mode protocol sniffer connected
+   * to the device.  This trace source fire on packets destined for any host
+   * just like your average everyday packet sniffer.
+   *
+   * On the transmit size, this trace hook will fire after a packet is dequeued
+   * from the device queue for transmission.  In Linux, for example, this would
+   * correspond to the point just before a device hard_start_xmit where 
+   * dev_queue_xmit_nit is called to dispatch the packet to the PF_PACKET 
+   * ETH_P_ALL handlers.
+   *
+   * On the receive side, this trace hook will fire when a packet is received,
+   * just before the receive callback is executed.  In Linux, for example, 
+   * this would correspond to the point at which the packet is dispatched to 
+   * packet sniffers in netif_receive_skb.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_promiscSnifferTrace;
 
   /**
    * Time to start spinning up the device
--- a/src/devices/point-to-point/point-to-point-channel.h	Wed Feb 25 12:27:00 2009 -0500
+++ b/src/devices/point-to-point/point-to-point-channel.h	Sat Feb 28 16:25:24 2009 -0800
@@ -62,13 +62,13 @@
   void Attach (Ptr<PointToPointNetDevice> device);
 
   /**
-   * \brief Attach a given netdevice to this channel
+   * \brief Transmit a packet over this channel
    * \param p Packet to transmit
    * \param src Source PointToPointNetDevice
    * \param txTime Transmit time to apply
+   * \returns true if successful (currently always true)
    */
-  bool TransmitStart (Ptr<Packet> p, Ptr<PointToPointNetDevice> src,
-    Time txTime);
+  bool TransmitStart (Ptr<Packet> p, Ptr<PointToPointNetDevice> src, Time txTime);
 
   /**
    * \brief Get number of devices on this channel
--- a/src/devices/point-to-point/point-to-point-net-device.cc	Wed Feb 25 12:27:00 2009 -0500
+++ b/src/devices/point-to-point/point-to-point-net-device.cc	Sat Feb 28 16:25:24 2009 -0800
@@ -62,23 +62,67 @@
                    PointerValue (),
                    MakePointerAccessor (&PointToPointNetDevice::m_receiveErrorModel),
                    MakePointerChecker<ErrorModel> ())
-    .AddAttribute ("TxQueue",
-                   "A queue to use as the transmit queue in the device.",
-                   PointerValue (),
-                   MakePointerAccessor (&PointToPointNetDevice::m_queue),
-                   MakePointerChecker<Queue> ())
     .AddAttribute ("InterframeGap", 
                    "The time to wait between packet (frame) transmissions",
                    TimeValue (Seconds (0.0)),
                    MakeTimeAccessor (&PointToPointNetDevice::m_tInterframeGap),
                    MakeTimeChecker ())
-    .AddTraceSource ("Rx", 
-                     "Trace source indicating reception of packet from the PointToPointChannel.",
-                     MakeTraceSourceAccessor (&PointToPointNetDevice::m_rxTrace))
-    .AddTraceSource ("Drop",
-                     "Trace source indicating a packet was discarded due to a ReceiveErrorModel decision.",
-                     MakeTraceSourceAccessor (&PointToPointNetDevice::m_dropTrace))
+
+    //
+    // Transmit queueing discipline for the device which includes its own set
+    // of trace hooks.
+    //
+    .AddAttribute ("TxQueue", 
+                   "A queue to use as the transmit queue in the device.",
+                   PointerValue (),
+                   MakePointerAccessor (&PointToPointNetDevice::m_queue),
+                   MakePointerChecker<Queue> ())
 
+    //
+    // Trace sources at the "top" of the net device, where packets transition
+    // to/from higher layers.
+    //
+    .AddTraceSource ("MacTx", 
+                     "Trace source indicating a packet has arrived for transmission by this device",
+                     MakeTraceSourceAccessor (&PointToPointNetDevice::m_macTxTrace))
+    .AddTraceSource ("MacTxDrop", 
+                     "Trace source indicating a packet has been dropped by the device before transmission",
+                     MakeTraceSourceAccessor (&PointToPointNetDevice::m_macTxDropTrace))
+    .AddTraceSource ("MacRx", 
+                     "Trace source indicating a packet has been received by this device and is being forwarded up the stack",
+                     MakeTraceSourceAccessor (&PointToPointNetDevice::m_macRxTrace))
+    //
+    // Trace souces at the "bottom" of the net device, where packets transition
+    // to/from the channel.
+    //
+    .AddTraceSource ("PhyTxStart", 
+                     "Trace source indicating a packet has begun transmitting over the channel",
+                     MakeTraceSourceAccessor (&PointToPointNetDevice::m_phyTxStartTrace))
+    .AddTraceSource ("PhyTx", 
+                     "Trace source indicating a packet has been completely transmitted over the channel",
+                     MakeTraceSourceAccessor (&PointToPointNetDevice::m_phyTxTrace))
+    .AddTraceSource ("PhyTxDrop", 
+                     "Trace source indicating a packet has been dropped by the device during transmission",
+                     MakeTraceSourceAccessor (&PointToPointNetDevice::m_phyTxDropTrace))
+    .AddTraceSource ("PhyRxStart", 
+                     "Trace source indicating a packet has begun being received by the device",
+                     MakeTraceSourceAccessor (&PointToPointNetDevice::m_phyRxStartTrace))
+    .AddTraceSource ("PhyRx", 
+                     "Trace source indicating a packet has been completely received by the device",
+                     MakeTraceSourceAccessor (&PointToPointNetDevice::m_phyRxTrace))
+    .AddTraceSource ("PhyRxDrop", 
+                     "Trace source indicating a packet has been dropped by the device during reception",
+                     MakeTraceSourceAccessor (&PointToPointNetDevice::m_phyRxDropTrace))
+
+    //
+    // Trace sources designed to simulate a packet sniffer facility (tcpdump).
+    //
+    .AddTraceSource ("Sniffer", 
+                     "Trace source simulating a non-promiscuous packet sniffer attached to the device",
+                     MakeTraceSourceAccessor (&PointToPointNetDevice::m_snifferTrace))
+    .AddTraceSource ("PromiscSniffer", 
+                     "Trace source simulating a promiscuous packet sniffer attached to the device",
+                     MakeTraceSourceAccessor (&PointToPointNetDevice::m_promiscSnifferTrace))
     ;
   return tid;
 }
@@ -89,7 +133,8 @@
   m_txMachineState (READY),
   m_channel (0), 
   m_name (""),
-  m_linkUp (false)
+  m_linkUp (false),
+  m_currentPkt (0)
 {
   NS_LOG_FUNCTION (this);
 
@@ -112,8 +157,7 @@
 PointToPointNetDevice::AddHeader(Ptr<Packet> p, uint16_t protocolNumber)
 {
   NS_LOG_FUNCTION_NOARGS ();
-  NS_ASSERT_MSG (protocolNumber == 0x800,
-    "PointToPointNetDevice::AddHeader(): protocolNumber must be 0x800");
+  NS_ASSERT_MSG (protocolNumber == 0x800, "PointToPointNetDevice::AddHeader(): protocolNumber must be 0x800");
   PppHeader ppp;
   p->AddHeader (ppp);
 }
@@ -135,6 +179,7 @@
   m_node = 0;
   m_channel = 0;
   m_receiveErrorModel = 0;
+  m_currentPkt = 0;
   NetDevice::DoDispose ();
 }
 
@@ -157,48 +202,63 @@
 {
   NS_LOG_FUNCTION (this << 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.
-//
+
+  //
+  // 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;
+  m_phyTxTrace (m_currentPkt);
+  m_currentPkt = p;
+
   Time txTime = Seconds (m_bps.CalculateTxTime(p->GetSize()));
   Time txCompleteTime = txTime + m_tInterframeGap;
 
-  NS_LOG_LOGIC ("Schedule TransmitCompleteEvent in " << 
-    txCompleteTime.GetSeconds () << "sec");
+  NS_LOG_LOGIC ("Schedule TransmitCompleteEvent in " << txCompleteTime.GetSeconds () << "sec");
+  Simulator::Schedule (txCompleteTime, &PointToPointNetDevice::TransmitComplete, this);
 
-  Simulator::Schedule (txCompleteTime, 
-    &PointToPointNetDevice::TransmitComplete, this);
-
-  return m_channel->TransmitStart(p, this, txTime); 
+  bool result = m_channel->TransmitStart(p, this, txTime); 
+  if (result == false)
+    {
+      m_phyTxDropTrace (p);
+    }
+  return result;
 }
 
   void 
 PointToPointNetDevice::TransmitComplete (void)
 {
   NS_LOG_FUNCTION_NOARGS ();
-//
-// This function is called to when we're all done transmitting a packet.
-// We try and pull another packet off of the transmit queue.  If the queue
-// is empty, we are done, otherwise we need to start transmitting the
-// next packet.
-//
+
+  //
+  // This function is called to when we're all done transmitting a packet.
+  // We try and pull another packet off of the transmit queue.  If the queue
+  // is empty, we are done, otherwise we need to start transmitting the
+  // next packet.
+  //
   NS_ASSERT_MSG(m_txMachineState == BUSY, "Must be BUSY if transmitting");
   m_txMachineState = READY;
+
+  NS_ASSERT_MSG (m_currentPkt != 0, "PointToPointNetDevice::TransmitComplete(): m_currentPkt zero");
+
+  m_phyTxTrace (m_currentPkt);
+  m_currentPkt = 0;
+
   Ptr<Packet> p = m_queue->Dequeue ();
   if (p == 0)
     {
-//
-// No packet was on the queue, so we just exit.
-//
+      //
+      // No packet was on the queue, so we just exit.
+      //
       return;
     }
-//
-// Got another packet off of the queue, so start the transmit process agin.
-//
+
+  //
+  // Got another packet off of the queue, so start the transmit process agin.
+  //
+  m_snifferTrace (p);
   TransmitStart(p);
 }
 
@@ -211,11 +271,11 @@
 
   m_channel->Attach(this);
 
-//
-// This device is up whenever it is attached to a channel.  A better plan
-// would be to have the link come up when both devices are attached, but this
-// is not done for now.
-//
+  //
+  // This device is up whenever it is attached to a channel.  A better plan
+  // would be to have the link come up when both devices are attached, but this
+  // is not done for now.
+  //
   NotifyLinkUp ();
   return true;
 }
@@ -242,25 +302,37 @@
 
   if (m_receiveErrorModel && m_receiveErrorModel->IsCorrupt (packet) ) 
     {
-// 
-// If we have an error model and it indicates that it is time to lose a
-// corrupted packet, don't forward this packet up, let it go.
-//
-      m_dropTrace (packet);
+      // 
+      // If we have an error model and it indicates that it is time to lose a
+      // corrupted packet, don't forward this packet up, let it go.
+      //
+      m_phyRxDropTrace (packet);
     }
   else 
     {
-// 
-// Hit the receive trace hook, strip off the point-to-point protocol header
-// and forward this packet up the protocol stack.
-//
-      m_rxTrace (packet);
+      // 
+      // Hit the trace hooks.  All of these hooks are in the same place in this 
+      // device becuase it is so simple, but this is not usually the case.  
+      //
+      m_snifferTrace (packet);
+      m_phyRxTrace (packet);
+      m_macRxTrace (packet);
+
+      //
+      // Strip off the point-to-point protocol header and forward this packet
+      // up the protocol stack.  Since this is a simple point-to-point link,
+      // there is no difference in what the promisc callback sees and what the
+      // normal receive callback sees.
+      //
       ProcessHeader(packet, protocol);
-      m_rxCallback (this, packet, protocol, GetRemote ());
+
       if (!m_promiscCallback.IsNull ())
         {
-          m_promiscCallback (this, packet, protocol, GetRemote (), GetAddress (), NetDevice::PACKET_HOST);
+          Ptr<Packet> pktCopy = packet->Copy ();
+          m_promiscCallback (this, pktCopy, protocol, GetRemote (), GetAddress (), NetDevice::PACKET_HOST);
         }
+
+      m_rxCallback (this, packet, protocol, GetRemote ());
     }
 }
 
@@ -406,33 +478,37 @@
   NS_LOG_LOGIC ("p=" << packet << ", dest=" << &dest);
   NS_LOG_LOGIC ("UID is " << packet->GetUid ());
 
-//
-// If IsLinkUp() is false it means there is no channel to send any packet 
-// over so we just return an error.
-//
+  //
+  // If IsLinkUp() is false it means there is no channel to send any packet 
+  // over so we just hit the drop trace on the packet and return an error.
+  //
   if (IsLinkUp () == false)
     {
+      m_macTxDropTrace (packet);
       return false;
     }
 
-//
-// Stick a point to point protocol header on the packet in preparation for
-// shoving it out the door.
-//
+  //
+  // Stick a point to point protocol header on the packet in preparation for
+  // shoving it out the door.
+  //
   AddHeader(packet, protocolNumber);
 
-//
-// If there's a transmission in progress, we enque the packet for later
-// transmission; otherwise we send it now.
-//
+  m_macTxTrace (packet);
+
+  //
+  // If there's a transmission in progress, we enque the packet for later
+  // transmission; otherwise we send it now.
+  //
   if (m_txMachineState == READY) 
     {
-// 
-// Even if the transmitter is immediately available, we still enqueue and 
-// dequeue the packet to hit the tracing hooks.
-//
+      // 
+      // Even if the transmitter is immediately available, we still enqueue and
+      // dequeue the packet to hit the tracing hooks.
+      //
       m_queue->Enqueue (packet);
       packet = m_queue->Dequeue ();
+      m_snifferTrace (packet);
       return TransmitStart (packet);
     }
   else
--- a/src/devices/point-to-point/point-to-point-net-device.h	Wed Feb 25 12:27:00 2009 -0500
+++ b/src/devices/point-to-point/point-to-point-net-device.h	Sat Feb 28 16:25:24 2009 -0800
@@ -388,26 +388,127 @@
   Ptr<Queue> m_queue;
 
   /**
-   * The trace source for the packet reception events that the device can
-   * fire.
-   *
-   * @see class CallBackTraceSource
-   */
-  TracedCallback<Ptr<const Packet> > m_rxTrace;
-
-  /**
-   * The trace source for the packet drop events that the device can
-   * fire.
-   *
-   * @see class CallBackTraceSource
-   */
-  TracedCallback<Ptr<const Packet> > m_dropTrace;
-
-  /**
    * Error model for receive packet events
    */
   Ptr<ErrorModel> m_receiveErrorModel;
 
+  /**
+   * The trace source fired when packets come into the "top" of the device
+   * at the L3/L2 transition, before being queued for transmission.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_macTxTrace;
+
+  /**
+   * The trace source fired when packets coming into the "top" of the device
+   * at the L3/L2 transition are dropped before being queued for transmission.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_macTxDropTrace;
+
+  /**
+   * The trace source fired for packets successfully received by the device
+   * immediately before being forwarded up to higher layers (at the L2/L3 
+   * transition).
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_macRxTrace;
+
+  /**
+   * The trace source fired when a packet starts the transmission process on
+   * the medium.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_phyTxStartTrace;
+
+  /**
+   * The trace source fired when a packet ends the transmission process on
+   * the medium.  This happens immediately after the device has completed
+   * packet transmission and has stopped "wiggling" the wire.  N.B. This
+   * is not the same time that the packet will be received on a remote device
+   * as that time includes a speed-of-light delay.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_phyTxTrace;
+
+  /**
+   * The trace source fired when the phy layer drops a packet before it tries
+   * to transmit it.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_phyTxDropTrace;
+
+  /**
+   * The trace source fired when a packet starts the reception process from
+   * the medium -- when the simulated first bit(s) arrive.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_phyRxStartTrace;
+
+  /**
+   * The trace source fired when a packet ends the reception process from
+   * the medium.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_phyRxTrace;
+
+  /**
+   * The trace source fired when the phy layer drops a packet it has received.
+   * This happens if the receiver is not enabled or the error model is active
+   * and indicates that the packet is corrupt.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_phyRxDropTrace;
+
+  /**
+   * A trace source that emulates a non-promiscuous protocol sniffer connected 
+   * to the device.  Unlike your average everyday sniffer, this trace source 
+   * will not fire on PACKET_OTHERHOST events.
+   *
+   * On the transmit size, this trace hook will fire after a packet is dequeued
+   * from the device queue for transmission.  In Linux, for example, this would
+   * correspond to the point just before a device hard_start_xmit where 
+   * dev_queue_xmit_nit is called to dispatch the packet to the PF_PACKET 
+   * ETH_P_ALL handlers.
+   *
+   * On the receive side, this trace hook will fire when a packet is received,
+   * just before the receive callback is executed.  In Linux, for example, 
+   * this would correspond to the point at which the packet is dispatched to 
+   * packet sniffers in netif_receive_skb.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_snifferTrace;
+
+  /**
+   * A trace source that emulates a promiscuous mode protocol sniffer connected
+   * to the device.  This trace source fire on packets destined for any host
+   * just like your average everyday packet sniffer.
+   *
+   * On the transmit size, this trace hook will fire after a packet is dequeued
+   * from the device queue for transmission.  In Linux, for example, this would
+   * correspond to the point just before a device hard_start_xmit where 
+   * dev_queue_xmit_nit is called to dispatch the packet to the PF_PACKET 
+   * ETH_P_ALL handlers.
+   *
+   * On the receive side, this trace hook will fire when a packet is received,
+   * just before the receive callback is executed.  In Linux, for example, 
+   * this would correspond to the point at which the packet is dispatched to 
+   * packet sniffers in netif_receive_skb.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_promiscSnifferTrace;
+
   Ptr<Node> m_node;
   Mac48Address m_address;
   NetDevice::ReceiveCallback m_rxCallback;
@@ -435,6 +536,8 @@
    * Ethernet.
    */
   uint32_t m_mtu;
+
+  Ptr<Packet> m_currentPkt;
 };
 
 } // namespace ns3
--- a/src/devices/wifi/adhoc-wifi-mac.cc	Wed Feb 25 12:27:00 2009 -0500
+++ b/src/devices/wifi/adhoc-wifi-mac.cc	Sat Feb 28 16:25:24 2009 -0800
@@ -24,6 +24,7 @@
 #include "mac-rx-middle.h"
 #include "wifi-phy.h"
 #include "dcf-manager.h"
+#include "wifi-mac-trailer.h"
 #include "ns3/pointer.h"
 #include "ns3/packet.h"
 #include "ns3/log.h"
@@ -234,6 +235,7 @@
       destination->RecordDisassociated ();
     }
 
+  m_macTxTrace (packet);
   m_dca->Queue (packet, hdr);
 }
 bool 
@@ -246,6 +248,7 @@
 AdhocWifiMac::ForwardUp (Ptr<Packet> packet, WifiMacHeader const *hdr)
 {
   NS_LOG_DEBUG ("received size="<<packet->GetSize ()<<", from="<<hdr->GetAddr2 ());
+  m_macRxTrace (packet);
   m_upCallback (packet, hdr->GetAddr2 (), hdr->GetAddr1 ());
 }
 Ptr<DcaTxop>
--- a/src/devices/wifi/mac-low.cc	Wed Feb 25 12:27:00 2009 -0500
+++ b/src/devices/wifi/mac-low.cc	Sat Feb 28 16:25:24 2009 -0800
@@ -840,6 +840,10 @@
    */
   Time txDuration = m_phy->CalculateTxDuration (packet->GetSize (), txMode, WIFI_PREAMBLE_LONG);
   Simulator::Schedule (txDuration, &MacLow::NotifyNav, this, *hdr, txMode, WIFI_PREAMBLE_LONG);
+  /*
+   * Tell the phy when we expect the packet has completely been sent -- for tracing
+   */
+  Simulator::Schedule (txDuration, &WifiPhy::SendDone, m_phy, packet);
 }
 
 void
--- a/src/devices/wifi/nqap-wifi-mac.cc	Wed Feb 25 12:27:00 2009 -0500
+++ b/src/devices/wifi/nqap-wifi-mac.cc	Sat Feb 28 16:25:24 2009 -0800
@@ -30,6 +30,7 @@
 #include "dcf-manager.h"
 #include "mac-rx-middle.h"
 #include "mac-low.h"
+#include "wifi-mac-trailer.h"
 #include "ns3/pointer.h"
 
 NS_LOG_COMPONENT_DEFINE ("NqapWifiMac");
@@ -285,8 +286,10 @@
 NqapWifiMac::ForwardUp (Ptr<Packet> packet, Mac48Address from, Mac48Address to)
 {
   NS_LOG_FUNCTION (this << packet << from);
+  m_macRxTrace (packet);
   m_upCallback (packet, from, to);
 }
+
 void 
 NqapWifiMac::ForwardDown (Ptr<const Packet> packet, Mac48Address from, Mac48Address to)
 {
@@ -298,6 +301,8 @@
   hdr.SetAddr3 (from);
   hdr.SetDsFrom ();
   hdr.SetDsNotTo ();
+
+  m_macTxTrace (packet);
   m_dca->Queue (packet, hdr);  
 }
 void 
@@ -472,11 +477,13 @@
         {
           // this is an AP-to-AP frame
           // we ignore for now.
+          m_macRxDropTrace (packet);
         } 
       else 
         {
           // we can ignore these frames since 
           // they are not targeted at the AP
+          m_macRxDropTrace (packet);
         }
     } 
   else if (hdr->IsMgt ()) 
--- a/src/devices/wifi/nqsta-wifi-mac.cc	Wed Feb 25 12:27:00 2009 -0500
+++ b/src/devices/wifi/nqsta-wifi-mac.cc	Sat Feb 28 16:25:24 2009 -0800
@@ -34,6 +34,7 @@
 #include "mac-low.h"
 #include "dcf-manager.h"
 #include "mac-rx-middle.h"
+#include "wifi-mac-trailer.h"
 #include "ns3/trace-source-accessor.h"
 #include "ns3/pointer.h"
 
@@ -321,6 +322,7 @@
 NqstaWifiMac::ForwardUp (Ptr<Packet> packet, Mac48Address from, Mac48Address to)
 {
   NS_LOG_FUNCTION (this << packet << from << to);
+  m_macRxTrace (packet);
   m_forwardUp (packet, from, to);
 }
 void
@@ -457,14 +459,16 @@
 void 
 NqstaWifiMac::Enqueue (Ptr<const Packet> packet, Mac48Address to, Mac48Address from)
 {
-  NS_FATAL_ERROR ("Qsta does not support enqueue");
+  NS_FATAL_ERROR ("Qsta does not support SendTo");
 }
+
 void 
 NqstaWifiMac::Enqueue (Ptr<const Packet> packet, Mac48Address to)
 {
   NS_LOG_FUNCTION (this << packet << to);
   if (!IsAssociated ()) 
     {
+      m_macTxDropTrace (packet);
       TryToEnsureAssociated ();
       return;
     }
@@ -476,12 +480,19 @@
   hdr.SetAddr3 (to);
   hdr.SetDsNotFrom ();
   hdr.SetDsTo ();
+
+  m_macTxTrace (packet);
   m_dca->Queue (packet, hdr);
 }
+
 bool 
 NqstaWifiMac::SupportsSendFrom (void) const
 {
-  return true;
+  //
+  // The 802.11 MAC protocol has no way to support bridging outside of
+  // infrastructure mode
+  //
+  return false;
 }  
 
 
@@ -498,24 +509,29 @@
            !hdr->GetAddr1 ().IsGroup ()) 
     {
       NS_LOG_LOGIC ("packet is not for us");
+      m_macRxDropTrace (packet);
     } 
   else if (hdr->IsData ()) 
     {
       if (!IsAssociated ())
         {
           NS_LOG_LOGIC ("Received data frame while not associated: ignore");
+          m_macRxDropTrace (packet);
           return;
         }
       if (!(hdr->IsFromDs () && !hdr->IsToDs ()))
         {
           NS_LOG_LOGIC ("Received data frame not from the DS: ignore");
+          m_macRxDropTrace (packet);
           return;
         }
       if (hdr->GetAddr2 () != GetBssid ())
         {
           NS_LOG_LOGIC ("Received data frame not from the the BSS we are associated with: ignore");
+          m_macRxDropTrace (packet);
           return;
         }
+
       ForwardUp (packet, hdr->GetAddr3 (), hdr->GetAddr1 ());
     } 
   else if (hdr->IsProbeReq () ||
@@ -524,6 +540,7 @@
       /* this is a frame aimed at an AP.
        * so we can safely ignore it.
        */
+      m_macRxDropTrace (packet);
     } 
   else if (hdr->IsBeacon ()) 
     {
--- a/src/devices/wifi/wifi-mac.cc	Wed Feb 25 12:27:00 2009 -0500
+++ b/src/devices/wifi/wifi-mac.cc	Sat Feb 28 16:25:24 2009 -0800
@@ -19,6 +19,7 @@
  */
 #include "wifi-mac.h"
 #include "ns3/uinteger.h"
+#include "ns3/trace-source-accessor.h"
 
 namespace ns3 {
 
@@ -117,7 +118,26 @@
 		   MakeSsidAccessor (&WifiMac::GetSsid,
 				     &WifiMac::SetSsid),
 		   MakeSsidChecker ())
+    .AddTraceSource ("MacTx", 
+                     "A packet has been received from higher layers and is being processed in preparation for "
+                     "queueing for transmission.",
+                     MakeTraceSourceAccessor (&WifiMac::m_macTxTrace))
+    .AddTraceSource ("MacTxDrop", 
+                     "A packet has been dropped in the MAC layer before being queued for transmission.",
+                     MakeTraceSourceAccessor (&WifiMac::m_macTxDropTrace))
+    .AddTraceSource ("MacRx", 
+                     "A packet has been received by this device, has been passed up from the physical layer "
+                     "and is being forwarded up the local protocol stack.",
+                     MakeTraceSourceAccessor (&WifiMac::m_macRxTrace))
+    .AddTraceSource ("MacRxDrop", 
+                     "A packet has been dropped in the MAC layer after it has been passed up from the physical "
+                     "layer.",
+                     MakeTraceSourceAccessor (&WifiMac::m_macRxDropTrace))
+    .AddTraceSource ("Sniffer", 
+                     "Trace source simulating a non-promiscuous packet sniffer attached to the device",
+                     MakeTraceSourceAccessor (&WifiMac::m_snifferTrace))
     ;
+
   return tid;
 }
 
@@ -144,5 +164,11 @@
   return m_maxMsduSize;
 }
 
+void
+WifiMac::SnifferTrace (Ptr<const Packet> packet)
+{
+  m_snifferTrace (packet);
+}
+
 
 } // namespace ns3
--- a/src/devices/wifi/wifi-mac.h	Wed Feb 25 12:27:00 2009 -0500
+++ b/src/devices/wifi/wifi-mac.h	Sat Feb 28 16:25:24 2009 -0800
@@ -176,10 +176,14 @@
    * \param linkDown the callback to invoke when the link becomes down.
    */
   virtual void SetLinkDownCallback (Callback<void> linkDown) = 0;
-private:
 
+  /*
+   * Let the net device hit a trace hook.  This is done to group the high-level
+   * trace sources all in one place for ease of use.
+   */
+  void SnifferTrace (Ptr<const Packet> packet);
 
-
+private:
   static Time GetDefaultMaxPropagationDelay (void);
   static Time GetDefaultSlot (void);
   static Time GetDefaultSifs (void);
@@ -189,6 +193,61 @@
 
   Time m_maxPropagationDelay;
   uint32_t m_maxMsduSize;
+
+protected:
+
+  /**
+   * The trace source fired when packets come into the "top" of the device
+   * at the L3/L2 transition, before being queued for transmission.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_macTxTrace;
+
+  /**
+   * The trace source fired when packets coming into the "top" of the device
+   * are dropped at the MAC layer during transmission.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_macTxDropTrace;
+
+  /**
+   * The trace source fired for packets successfully received by the device
+   * immediately before being forwarded up to higher layers (at the L2/L3 
+   * transition).
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_macRxTrace;
+
+  /**
+   * The trace source fired when packets coming into the "top" of the device
+   * are dropped at the MAC layer during reception.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_macRxDropTrace;
+
+  /**
+   * A trace source that emulates a non-promiscuous protocol sniffer connected 
+   * to the device.  Unlike your average everyday sniffer, this trace source 
+   * will not fire on PACKET_OTHERHOST events.
+   *
+   * On the transmit size, this trace hook will fire after a packet is dequeued
+   * from the device queue for transmission.  In Linux, for example, this would
+   * correspond to the point just before a device hard_start_xmit where 
+   * dev_queue_xmit_nit is called to dispatch the packet to the PF_PACKET 
+   * ETH_P_ALL handlers.
+   *
+   * On the receive side, this trace hook will fire when a packet is received,
+   * just before the receive callback is executed.  In Linux, for example, 
+   * this would correspond to the point at which the packet is dispatched to 
+   * packet sniffers in netif_receive_skb.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_snifferTrace;
 };
 
 } // namespace ns3
--- a/src/devices/wifi/wifi-net-device.cc	Wed Feb 25 12:27:00 2009 -0500
+++ b/src/devices/wifi/wifi-net-device.cc	Sat Feb 28 16:25:24 2009 -0800
@@ -23,6 +23,8 @@
 #include "wifi-remote-station-manager.h"
 #include "wifi-channel.h"
 #include "ns3/llc-snap-header.h"
+#include "ns3/ethernet-header.h"
+#include "ns3/ethernet-trailer.h"
 #include "ns3/packet.h"
 #include "ns3/uinteger.h"
 #include "ns3/pointer.h"
@@ -57,10 +59,6 @@
                    MakePointerAccessor (&WifiNetDevice::SetRemoteStationManager,
                                         &WifiNetDevice::GetRemoteStationManager),
                    MakePointerChecker<WifiRemoteStationManager> ())
-    .AddTraceSource ("Rx", "Received payload from the MAC layer.",
-                     MakeTraceSourceAccessor (&WifiNetDevice::m_rxLogger))
-    .AddTraceSource ("Tx", "Send payload to the MAC layer.",
-                     MakeTraceSourceAccessor (&WifiNetDevice::m_txLogger))
     ;
   return tid;
 }
@@ -243,11 +241,14 @@
   return false;
 }
 bool 
-WifiNetDevice::Send(Ptr<Packet> packet, const Address& dest, uint16_t protocolNumber)
+WifiNetDevice::Send (Ptr<Packet> packet, const Address& dest, uint16_t protocolNumber)
 {
   NS_ASSERT (Mac48Address::IsMatchingType (dest));
 
   Mac48Address realTo = Mac48Address::ConvertFrom (dest);
+  Mac48Address realFrom = Mac48Address::ConvertFrom (GetAddress ());
+
+  SniffPacket (packet, realTo, realFrom, protocolNumber);
 
   LlcSnapHeader llc;
   llc.SetType (protocolNumber);
@@ -303,13 +304,16 @@
     {
       type = NetDevice::PACKET_OTHERHOST;
     }
+
   if (type != NetDevice::PACKET_OTHERHOST)
     {
+      SniffPacket (packet, to, from, llc.GetType ());
       m_forwardUp (this, packet, llc.GetType (), from);
     }
+
   if (!m_promiscRx.IsNull ())
     {
-      m_promiscRx (this, packet, llc.GetType (), from, to, type);
+      m_promiscRx (this, packet->Copy (), llc.GetType (), from, to, type);
     }
 }
 
@@ -341,6 +345,8 @@
   Mac48Address realTo = Mac48Address::ConvertFrom (dest);
   Mac48Address realFrom = Mac48Address::ConvertFrom (source);
 
+  SniffPacket (packet, realTo, realFrom, protocolNumber);
+
   LlcSnapHeader llc;
   llc.SetType (protocolNumber);
   packet->AddHeader (llc);
@@ -364,5 +370,26 @@
   return m_mac->SupportsSendFrom ();
 }
 
+void
+WifiNetDevice::SniffPacket (Ptr<const Packet> packet, Mac48Address to, Mac48Address from, uint16_t type)
+{
+  Ptr<Packet> copy = packet->Copy ();
+  EthernetHeader header (false);
+  header.SetSource (from);
+  header.SetDestination (to);
+
+  LlcSnapHeader llc;
+  llc.SetType (type);
+  copy->AddHeader (llc);
+
+  header.SetLengthType (copy->GetSize ());
+  copy->AddHeader (header);
+
+  EthernetTrailer trailer;
+  trailer.CalcFcs (copy);
+  copy->AddTrailer (trailer);
+  m_mac->SnifferTrace (copy);
+}
+
 } // namespace ns3
 
--- a/src/devices/wifi/wifi-net-device.h	Wed Feb 25 12:27:00 2009 -0500
+++ b/src/devices/wifi/wifi-net-device.h	Sat Feb 28 16:25:24 2009 -0800
@@ -118,8 +118,18 @@
   Ptr<WifiRemoteStationManager> m_stationManager;
   NetDevice::ReceiveCallback m_forwardUp;
   NetDevice::PromiscReceiveCallback m_promiscRx;
+
   TracedCallback<Ptr<const Packet>, Mac48Address> m_rxLogger;
   TracedCallback<Ptr<const Packet>, Mac48Address> m_txLogger;
+
+  /**
+   * At the top of the MAC level, we do what many folks do and make the wifi 
+   * packets look like Ethernet packets coming in and out of the "driver."  If
+   * you are interested in seeing all of the wifi details, you should use the
+   * much lower level PHY promiscuous sniffer trace.
+   */
+  void SniffPacket (Ptr<const Packet> packet, Mac48Address to, Mac48Address from, uint16_t type);
+
   uint32_t m_ifIndex;
   std::string m_name;
   bool m_linkUp;
--- a/src/devices/wifi/wifi-phy.cc	Wed Feb 25 12:27:00 2009 -0500
+++ b/src/devices/wifi/wifi-phy.cc	Sat Feb 28 16:25:24 2009 -0800
@@ -55,6 +55,27 @@
 {
   static TypeId tid = TypeId ("ns3::WifiPhy")
     .SetParent<Object> ()
+    .AddTraceSource ("PhyTxStart", 
+                     "Trace source indicating a packet has begun transmitting over the channel medium",
+                     MakeTraceSourceAccessor (&WifiPhy::m_phyTxStartTrace))
+    .AddTraceSource ("PhyTx", 
+                     "Trace source indicating a packet has been completely transmitted over the channel",
+                     MakeTraceSourceAccessor (&WifiPhy::m_phyTxTrace))
+    .AddTraceSource ("PhyTxDrop", 
+                     "Trace source indicating a packet has been dropped by the device during transmission",
+                     MakeTraceSourceAccessor (&WifiPhy::m_phyTxDropTrace))
+    .AddTraceSource ("PhyRxStart", 
+                     "Trace source indicating a packet has begun being received from the channel medium by the device",
+                     MakeTraceSourceAccessor (&WifiPhy::m_phyRxStartTrace))
+    .AddTraceSource ("PhyRx", 
+                     "Trace source indicating a packet has been completely received from the channel medium by the device",
+                     MakeTraceSourceAccessor (&WifiPhy::m_phyRxTrace))
+    .AddTraceSource ("PhyRxDrop", 
+                     "Trace source indicating a packet has been dropped by the device during reception",
+                     MakeTraceSourceAccessor (&WifiPhy::m_phyRxDropTrace))
+    .AddTraceSource ("PromiscSniffer", 
+                     "Trace source simulating a promiscuous packet sniffer attached to the device",
+                     MakeTraceSourceAccessor (&WifiPhy::m_promiscSnifferTrace))
     ;
   return tid;
 }
--- a/src/devices/wifi/wifi-phy.h	Wed Feb 25 12:27:00 2009 -0500
+++ b/src/devices/wifi/wifi-phy.h	Sat Feb 28 16:25:24 2009 -0800
@@ -30,6 +30,7 @@
 #include "wifi-mode.h"
 #include "wifi-preamble.h"
 #include "wifi-phy-standard.h"
+#include "ns3/traced-callback.h"
 
 
 namespace ns3 {
@@ -79,6 +80,7 @@
    * unless they have received a cca busy report.
    */
   virtual void NotifyTxStart (Time duration) = 0;
+
   /**
    * \param duration the expected busy duration.
    *
@@ -173,6 +175,13 @@
   virtual void SendPacket (Ptr<const Packet> packet, WifiMode mode, enum WifiPreamble preamble, uint8_t txPowerLevel) = 0;
 
   /**
+   * \param packet the packet that was sent
+   *
+   * Tell the PHY-level that MAC low believes it should have just completed the send.
+   */
+  virtual void SendDone (Ptr<const Packet> packet) = 0;
+
+  /**
    * \param listener the new listener
    *
    * Add the input listener to the list of objects to be notified of
@@ -250,6 +259,74 @@
   static WifiMode Get36mba (void);
   static WifiMode Get48mba (void);
   static WifiMode Get54mba (void);
+
+protected:
+  /**
+   * The trace source fired when a packet starts the transmission process on
+   * the medium.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_phyTxStartTrace;
+
+  /**
+   * The trace source fired when a packet ends the transmission process on
+   * the medium.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_phyTxTrace;
+
+  /**
+   * The trace source fired when the phy layer drops a packet as it tries
+   * to transmit it.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_phyTxDropTrace;
+
+  /**
+   * The trace source fired when a packet starts the reception process from
+   * the medium.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_phyRxStartTrace;
+
+  /**
+   * The trace source fired when a packet ends the reception process from
+   * the medium.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_phyRxTrace;
+
+  /**
+   * The trace source fired when the phy layer drops a packet it has received.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_phyRxDropTrace;
+
+  /**
+   * A trace source that emulates a promiscuous mode protocol sniffer connected
+   * to the device.  This trace source fire on packets destined for any host
+   * just like your average everyday packet sniffer.
+   *
+   * On the transmit size, this trace hook will fire after a packet is dequeued
+   * from the device queue for transmission.  In Linux, for example, this would
+   * correspond to the point just before a device hard_start_xmit where 
+   * dev_queue_xmit_nit is called to dispatch the packet to the PF_PACKET 
+   * ETH_P_ALL handlers.
+   *
+   * On the receive side, this trace hook will fire when a packet is received,
+   * just before the receive callback is executed.  In Linux, for example, 
+   * this would correspond to the point at which the packet is dispatched to 
+   * packet sniffers in netif_receive_skb.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_promiscSnifferTrace;
 };
 
 } // namespace ns3
--- a/src/devices/wifi/yans-wifi-phy.cc	Wed Feb 25 12:27:00 2009 -0500
+++ b/src/devices/wifi/yans-wifi-phy.cc	Sat Feb 28 16:25:24 2009 -0800
@@ -34,6 +34,7 @@
 #include "ns3/enum.h"
 #include "ns3/pointer.h"
 #include "ns3/net-device.h"
+#include "ns3/trace-source-accessor.h"
 #include <math.h>
 
 NS_LOG_COMPONENT_DEFINE ("YansWifiPhy");
@@ -322,6 +323,7 @@
   case YansWifiPhy::SYNC:
     NS_LOG_DEBUG ("drop packet because already in Sync (power="<<
                   rxPowerW<<"W)");
+    m_phyRxDropTrace (packet);
     if (endRx > Simulator::Now () + m_state->GetDelayUntilIdle ()) 
       {
         // that packet will be noise _after_ the reception of the
@@ -332,6 +334,7 @@
   case YansWifiPhy::TX:
     NS_LOG_DEBUG ("drop packet because already in Tx (power="<<
                   rxPowerW<<"W)");
+    m_phyRxDropTrace (packet);
     if (endRx > Simulator::Now () + m_state->GetDelayUntilIdle ()) 
       {
         // that packet will be noise _after_ the transmission of the
@@ -347,6 +350,7 @@
         // sync to signal
         m_state->SwitchToSync (rxDuration);
         NS_ASSERT (m_endSyncEvent.IsExpired ());
+        m_phyRxStartTrace (packet);
         m_endSyncEvent = Simulator::Schedule (rxDuration, &YansWifiPhy::EndSync, this, 
                                               packet,
                                               event);
@@ -355,6 +359,7 @@
       {
         NS_LOG_DEBUG ("drop packet because signal power too Small ("<<
                       rxPowerW<<"<"<<m_edThresholdW<<")");
+        m_phyRxDropTrace (packet);
         goto maybeCcaBusy;
       }
     break;
@@ -374,6 +379,7 @@
       m_state->SwitchMaybeToCcaBusy (delayUntilCcaEnd);
     }
 }
+
 void 
 YansWifiPhy::SendPacket (Ptr<const Packet> packet, WifiMode txMode, WifiPreamble preamble, uint8_t txPower)
 {
@@ -391,10 +397,18 @@
     {
       m_endSyncEvent.Cancel ();
     }
+  m_phyTxStartTrace (packet);
+  m_promiscSnifferTrace (packet);
   m_state->SwitchToTx (txDuration, packet, txMode, preamble, txPower);
   m_channel->Send (this, packet, GetPowerDbm (txPower) + m_txGainDb, txMode, preamble);
 }
 
+void
+YansWifiPhy::SendDone (Ptr<const Packet> packet)
+{
+  m_phyTxTrace (packet);
+}
+
 uint32_t 
 YansWifiPhy::GetNModes (void) const
 {
@@ -550,11 +564,14 @@
   
   if (m_random.GetValue () > snrPer.per) 
     {
+      m_phyRxTrace (packet);
+      m_promiscSnifferTrace (packet);
       m_state->SwitchFromSyncEndOk (packet, snrPer.snr, event->GetPayloadMode (), event->GetPreambleType ());
     } 
   else 
     {
       /* failure. */
+      m_phyRxDropTrace (packet);
       m_state->SwitchFromSyncEndError (packet, snrPer.snr);
     }
 }
--- a/src/devices/wifi/yans-wifi-phy.h	Wed Feb 25 12:27:00 2009 -0500
+++ b/src/devices/wifi/yans-wifi-phy.h	Sat Feb 28 16:25:24 2009 -0800
@@ -102,6 +102,7 @@
   virtual void SetReceiveOkCallback (WifiPhy::SyncOkCallback callback);
   virtual void SetReceiveErrorCallback (WifiPhy::SyncErrorCallback callback);
   virtual void SendPacket (Ptr<const Packet> packet, WifiMode mode, enum WifiPreamble preamble, uint8_t txPowerLevel);
+  virtual void SendDone (Ptr<const Packet> packet);
   virtual void RegisterListener (WifiPhyListener *listener);
   virtual bool IsStateCcaBusy (void);
   virtual bool IsStateIdle (void);
@@ -134,6 +135,54 @@
   void EndSync (Ptr<Packet> packet, Ptr<InterferenceHelper::Event> event);
 
 private:
+  /**
+   * The trace source fired when a packet starts the transmission process on
+   * the medium.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_phyTxStartTrace;
+
+  /**
+   * The trace source fired when a packet ends the transmission process on
+   * the medium.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_phyTxTrace;
+
+  /**
+   * The trace source fired when the phy layer drops a packet as it tries
+   * to transmit it.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_phyTxDropTrace;
+
+  /**
+   * The trace source fired when a packet ends the reception process from
+   * the medium.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_phyRxTrace;
+
+  /**
+   * The trace source fired when a packet ends the reception process from
+   * the medium.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_phyRxStartTrace;
+
+  /**
+   * The trace source fired when the phy layer drops a packet it has received.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_phyRxDropTrace;
+
+private:
   double   m_edThresholdW;
   double   m_ccaMode1ThresholdW;
   double   m_txGainDb;
@@ -151,6 +200,7 @@
   WifiPhyStandard m_standard;
   Ptr<WifiPhyStateHelper> m_state;
   InterferenceHelper m_interference;
+
 };
 
 } // namespace ns3
--- a/src/helper/csma-helper.cc	Wed Feb 25 12:27:00 2009 -0500
+++ b/src/helper/csma-helper.cc	Sat Feb 28 16:25:24 2009 -0800
@@ -69,6 +69,7 @@
 {
   SetDeviceAttribute (n1, v1);
 }
+
 void 
 CsmaHelper::SetChannelParameter (std::string n1, const AttributeValue &v1)
 {
@@ -91,12 +92,10 @@
   pcap->Open (oss.str ());
   pcap->WriteEthernetHeader ();
   oss.str ("");
-  oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::CsmaNetDevice/Rx";
-  Config::ConnectWithoutContext (oss.str (), MakeBoundCallback (&CsmaHelper::RxEvent, pcap));
-  oss.str ("");
-  oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::CsmaNetDevice/TxQueue/Enqueue";
-  Config::ConnectWithoutContext (oss.str (), MakeBoundCallback (&CsmaHelper::EnqueueEvent, pcap));
+  oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::CsmaNetDevice/Sniffer";
+  Config::ConnectWithoutContext (oss.str (), MakeBoundCallback (&CsmaHelper::SniffEvent, pcap));
 }
+
 void 
 CsmaHelper::EnablePcap (std::string filename, NetDeviceContainer d)
 {
@@ -132,7 +131,7 @@
 {
   Packet::EnablePrinting ();
   std::ostringstream oss;
-  oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::CsmaNetDevice/Rx";
+  oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::CsmaNetDevice/MacRx";
   Config::Connect (oss.str (), MakeBoundCallback (&CsmaHelper::AsciiRxEvent, &os));
   oss.str ("");
   oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::CsmaNetDevice/TxQueue/Enqueue";
@@ -279,15 +278,11 @@
 }
 
 void 
-CsmaHelper::EnqueueEvent (Ptr<PcapWriter> writer, Ptr<const Packet> packet)
+CsmaHelper::SniffEvent (Ptr<PcapWriter> writer, Ptr<const Packet> packet)
 {
   writer->WritePacket (packet);
 }
-void 
-CsmaHelper::RxEvent (Ptr<PcapWriter> writer, Ptr<const Packet> packet)
-{
-  writer->WritePacket (packet);
-}
+
 void 
 CsmaHelper::AsciiEnqueueEvent (std::ostream *os, std::string path, Ptr<const Packet> packet)
 {
--- a/src/helper/csma-helper.h	Wed Feb 25 12:27:00 2009 -0500
+++ b/src/helper/csma-helper.h	Sat Feb 28 16:25:24 2009 -0800
@@ -331,12 +331,13 @@
 private:
   Ptr<NetDevice> InstallPriv (Ptr<Node> node, Ptr<CsmaChannel> channel) const;
 
-  static void RxEvent (Ptr<PcapWriter> writer, Ptr<const Packet> packet);
-  static void EnqueueEvent (Ptr<PcapWriter> writer, Ptr<const Packet> packet);
+  static void SniffEvent (Ptr<PcapWriter> writer, Ptr<const Packet> packet);
+
+  static void AsciiRxEvent (std::ostream *os, std::string path, Ptr<const Packet> packet);
   static void AsciiEnqueueEvent (std::ostream *os, std::string path, Ptr<const Packet> packet);
   static void AsciiDequeueEvent (std::ostream *os, std::string path, Ptr<const Packet> packet);
   static void AsciiDropEvent (std::ostream *os, std::string path, Ptr<const Packet> packet);
-  static void AsciiRxEvent (std::ostream *os, std::string path, Ptr<const Packet> packet);
+
   ObjectFactory m_queueFactory;
   ObjectFactory m_deviceFactory;
   ObjectFactory m_channelFactory;
--- a/src/helper/emu-helper.cc	Wed Feb 25 12:27:00 2009 -0500
+++ b/src/helper/emu-helper.cc	Sat Feb 28 16:25:24 2009 -0800
@@ -78,16 +78,8 @@
   pcap->WriteEthernetHeader ();
 
   oss.str ("");
-  oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << 
-    "/$ns3::EmuNetDevice/Rx";
-  Config::ConnectWithoutContext (oss.str (), 
-    MakeBoundCallback (&EmuHelper::RxEvent, pcap));
-
-  oss.str ("");
-  oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << 
-    "/$ns3::EmuNetDevice/TxQueue/Enqueue";
-  Config::ConnectWithoutContext (oss.str (), 
-    MakeBoundCallback (&EmuHelper::EnqueueEvent, pcap));
+  oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::EmuNetDevice/Sniffer";
+  Config::ConnectWithoutContext (oss.str (), MakeBoundCallback (&EmuHelper::SniffEvent, pcap));
 }
 
   void 
@@ -131,28 +123,20 @@
   Packet::EnablePrinting ();
   std::ostringstream oss;
 
-  oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << 
-    "/$ns3::EmuNetDevice/Rx";
-  Config::Connect (oss.str (), 
-    MakeBoundCallback (&EmuHelper::AsciiRxEvent, &os));
+  oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::EmuNetDevice/MacRx";
+  Config::Connect (oss.str (), MakeBoundCallback (&EmuHelper::AsciiRxEvent, &os));
 
   oss.str ("");
-  oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << 
-    "/$ns3::EmuNetDevice/TxQueue/Enqueue";
-  Config::Connect (oss.str (), 
-    MakeBoundCallback (&EmuHelper::AsciiEnqueueEvent, &os));
+  oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::EmuNetDevice/TxQueue/Enqueue";
+  Config::Connect (oss.str (), MakeBoundCallback (&EmuHelper::AsciiEnqueueEvent, &os));
 
   oss.str ("");
-  oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << 
-    "/$ns3::EmuNetDevice/TxQueue/Dequeue";
-  Config::Connect (oss.str (), 
-    MakeBoundCallback (&EmuHelper::AsciiDequeueEvent, &os));
+  oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::EmuNetDevice/TxQueue/Dequeue";
+  Config::Connect (oss.str (), MakeBoundCallback (&EmuHelper::AsciiDequeueEvent, &os));
 
   oss.str ("");
-  oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << 
-    "/$ns3::EmuNetDevice/TxQueue/Drop";
-  Config::Connect (oss.str (), 
-    MakeBoundCallback (&EmuHelper::AsciiDropEvent, &os));
+  oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::EmuNetDevice/TxQueue/Drop";
+  Config::Connect (oss.str (), MakeBoundCallback (&EmuHelper::AsciiDropEvent, &os));
 }
 
   void 
@@ -228,14 +212,7 @@
 }
 
   void 
-EmuHelper::EnqueueEvent (Ptr<PcapWriter> writer, Ptr<const Packet> packet)
-{
-  NS_LOG_FUNCTION (writer << packet);
-  writer->WritePacket (packet);
-}
-
-  void 
-EmuHelper::RxEvent (Ptr<PcapWriter> writer, Ptr<const Packet> packet)
+EmuHelper::SniffEvent (Ptr<PcapWriter> writer, Ptr<const Packet> packet)
 {
   NS_LOG_FUNCTION (writer << packet);
   writer->WritePacket (packet);
--- a/src/helper/emu-helper.h	Wed Feb 25 12:27:00 2009 -0500
+++ b/src/helper/emu-helper.h	Sat Feb 28 16:25:24 2009 -0800
@@ -184,16 +184,12 @@
 
 private:
   Ptr<NetDevice> InstallPriv (Ptr<Node> node) const;
-  static void RxEvent (Ptr<PcapWriter> writer, Ptr<const Packet> packet);
-  static void EnqueueEvent (Ptr<PcapWriter> writer, Ptr<const Packet> packet);
-  static void AsciiEnqueueEvent (std::ostream *os, std::string path, 
-    Ptr<const Packet> packet);
-  static void AsciiDequeueEvent (std::ostream *os, std::string path, 
-    Ptr<const Packet> packet);
-  static void AsciiDropEvent (std::ostream *os, std::string path, 
-    Ptr<const Packet> packet);
-  static void AsciiRxEvent (std::ostream *os, std::string path, 
-    Ptr<const Packet> packet);
+  static void SniffEvent (Ptr<PcapWriter> writer, Ptr<const Packet> packet);
+
+  static void AsciiRxEvent (std::ostream *os, std::string path, Ptr<const Packet> packet);
+  static void AsciiEnqueueEvent (std::ostream *os, std::string path, Ptr<const Packet> packet);
+  static void AsciiDequeueEvent (std::ostream *os, std::string path, Ptr<const Packet> packet);
+  static void AsciiDropEvent (std::ostream *os, std::string path, Ptr<const Packet> packet);
 
   ObjectFactory m_queueFactory;
   ObjectFactory m_deviceFactory;
--- a/src/helper/point-to-point-helper.cc	Wed Feb 25 12:27:00 2009 -0500
+++ b/src/helper/point-to-point-helper.cc	Sat Feb 28 16:25:24 2009 -0800
@@ -90,11 +90,8 @@
   pcap->Open (oss.str ());
   pcap->WritePppHeader ();
   oss.str ("");
-  oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::PointToPointNetDevice/Rx";
-  Config::ConnectWithoutContext (oss.str (), MakeBoundCallback (&PointToPointHelper::RxEvent, pcap));
-  oss.str ("");
-  oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::PointToPointNetDevice/TxQueue/Enqueue";
-  Config::ConnectWithoutContext (oss.str (), MakeBoundCallback (&PointToPointHelper::EnqueueEvent, pcap));
+  oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::PointToPointNetDevice/Sniffer";
+  Config::ConnectWithoutContext (oss.str (), MakeBoundCallback (&PointToPointHelper::SniffEvent, pcap));
 }
 void 
 PointToPointHelper::EnablePcap (std::string filename, NetDeviceContainer d)
@@ -131,7 +128,7 @@
 {
   Packet::EnablePrinting ();
   std::ostringstream oss;
-  oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::PointToPointNetDevice/Rx";
+  oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::PointToPointNetDevice/MacRx";
   Config::Connect (oss.str (), MakeBoundCallback (&PointToPointHelper::AsciiRxEvent, &os));
   oss.str ("");
   oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::PointToPointNetDevice/TxQueue/Enqueue";
@@ -247,12 +244,7 @@
 }
 
 void 
-PointToPointHelper::EnqueueEvent (Ptr<PcapWriter> writer, Ptr<const Packet> packet)
-{
-  writer->WritePacket (packet);
-}
-void 
-PointToPointHelper::RxEvent (Ptr<PcapWriter> writer, Ptr<const Packet> packet)
+PointToPointHelper::SniffEvent (Ptr<PcapWriter> writer, Ptr<const Packet> packet)
 {
   writer->WritePacket (packet);
 }
--- a/src/helper/point-to-point-helper.h	Wed Feb 25 12:27:00 2009 -0500
+++ b/src/helper/point-to-point-helper.h	Sat Feb 28 16:25:24 2009 -0800
@@ -261,13 +261,14 @@
 
 private:
   void EnablePcap (Ptr<Node> node, Ptr<NetDevice> device, Ptr<Queue> queue);
+  static void SniffEvent (Ptr<PcapWriter> writer, Ptr<const Packet> packet);
+
   void EnableAscii (Ptr<Node> node, Ptr<NetDevice> device);
-  static void RxEvent (Ptr<PcapWriter> writer, Ptr<const Packet> packet);
-  static void EnqueueEvent (Ptr<PcapWriter> writer, Ptr<const Packet> packet);
+  static void AsciiRxEvent (std::ostream *os, std::string path, Ptr<const Packet> packet);
   static void AsciiEnqueueEvent (std::ostream *os, std::string path, Ptr<const Packet> packet);
   static void AsciiDequeueEvent (std::ostream *os, std::string path, Ptr<const Packet> packet);
   static void AsciiDropEvent (std::ostream *os, std::string path, Ptr<const Packet> packet);
-  static void AsciiRxEvent (std::ostream *os, std::string path, Ptr<const Packet> packet);
+
   ObjectFactory m_queueFactory;
   ObjectFactory m_channelFactory;
   ObjectFactory m_deviceFactory;
--- a/src/helper/wifi-helper.cc	Wed Feb 25 12:27:00 2009 -0500
+++ b/src/helper/wifi-helper.cc	Sat Feb 28 16:25:24 2009 -0800
@@ -37,6 +37,61 @@
 
 namespace ns3 {
 
+static void PcapSnifferEvent (Ptr<PcapWriter> writer, Ptr<const Packet> packet)
+{
+  writer->WritePacket (packet);
+}
+
+void 
+WifiHelper::EnablePcap (std::string filename, uint32_t nodeid, uint32_t deviceid)
+{
+  std::ostringstream oss;
+  oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::WifiNetDevice/Mac/";
+  Config::MatchContainer matches = Config::LookupMatches (oss.str ());
+  if (matches.GetN () == 0)
+    {
+      return;
+    }
+  oss.str ("");
+  oss << filename << "-" << nodeid << "-" << deviceid << ".pcap";
+  Ptr<PcapWriter> pcap = Create<PcapWriter> ();
+  pcap->Open (oss.str ());
+  pcap->WriteEthernetHeader ();
+  oss.str ("");
+  oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::WifiNetDevice/Mac/Sniffer";
+  Config::ConnectWithoutContext (oss.str (), MakeBoundCallback (&PcapSnifferEvent, pcap));
+}
+
+void 
+WifiHelper::EnablePcap (std::string filename, NetDeviceContainer d)
+{
+  for (NetDeviceContainer::Iterator i = d.Begin (); i != d.End (); ++i)
+    {
+      Ptr<NetDevice> dev = *i;
+      EnablePcap (filename, dev->GetNode ()->GetId (), dev->GetIfIndex ());
+    }
+}
+void
+WifiHelper::EnablePcap (std::string filename, NodeContainer n)
+{
+  NetDeviceContainer devs;
+  for (NodeContainer::Iterator i = n.Begin (); i != n.End (); ++i)
+    {
+      Ptr<Node> node = *i;
+      for (uint32_t j = 0; j < node->GetNDevices (); ++j)
+        {
+          devs.Add (node->GetDevice (j));
+        }
+    }
+  EnablePcap (filename, devs);
+}
+
+void
+WifiHelper::EnablePcapAll (std::string filename)
+{
+  EnablePcap (filename, NodeContainer::GetGlobal ());
+}
+
 WifiPhyHelper::~WifiPhyHelper ()
 {}
 
--- a/src/helper/wifi-helper.h	Wed Feb 25 12:27:00 2009 -0500
+++ b/src/helper/wifi-helper.h	Sat Feb 28 16:25:24 2009 -0800
@@ -159,6 +159,43 @@
    * \returns a device container which contains all the devices created by this method.
    */
   NetDeviceContainer Install (const WifiPhyHelper &phy, std::string nodeName) const;
+  /**
+   * \param filename filename prefix to use for pcap files.
+   * \param nodeid the id of the node to generate pcap output for.
+   * \param deviceid the id of the device to generate pcap output for.
+   *
+   * Generate a pcap file which contains the link-level data observed
+   * by the specified deviceid within the specified nodeid. The pcap
+   * data is stored in the file prefix-nodeid-deviceid.pcap.
+   *
+   * This method should be invoked after the network topology has 
+   * been fully constructed.
+   */
+  static void EnablePcap (std::string filename, uint32_t nodeid, uint32_t deviceid);
+  /**
+   * \param filename filename prefix to use for pcap files.
+   * \param d container of devices of type ns3::WifiNetDevice
+   *
+   * Enable pcap output on each input device which is of the
+   * ns3::WifiNetDevice type.
+   */
+  static void EnablePcap (std::string filename, NetDeviceContainer d);
+  /**
+   * \param filename filename prefix to use for pcap files.
+   * \param n container of nodes.
+   *
+   * Enable pcap output on each device which is of the
+   * ns3::WifiNetDevice type and which is located in one of the 
+   * input nodes.
+   */
+  static void EnablePcap (std::string filename, NodeContainer n);
+  /**
+   * \param filename filename prefix to use for pcap files.
+   *
+   * Enable pcap output on each device which is of the
+   * ns3::WifiNetDevice type
+   */
+  static void EnablePcapAll (std::string filename);
 
 private:
   ObjectFactory m_stationManager;
--- a/src/helper/yans-wifi-helper.cc	Wed Feb 25 12:27:00 2009 -0500
+++ b/src/helper/yans-wifi-helper.cc	Sat Feb 28 16:25:24 2009 -0800
@@ -31,16 +31,7 @@
 
 namespace ns3 {
 
-static void PcapPhyTxEvent (Ptr<PcapWriter> writer, Ptr<const Packet> packet,
-                            WifiMode mode, WifiPreamble preamble, 
-                            uint8_t txLevel)
-{
-  writer->WritePacket (packet);
-}
-
-static void PcapPhyRxEvent (Ptr<PcapWriter> writer, 
-                            Ptr<const Packet> packet, double snr, WifiMode mode, 
-                            enum WifiPreamble preamble)
+static void PcapSnifferEvent (Ptr<PcapWriter> writer, Ptr<const Packet> packet)
 {
   writer->WritePacket (packet);
 }
@@ -229,11 +220,8 @@
   pcap->Open (oss.str ());
   pcap->WriteWifiHeader ();
   oss.str ("");
-  oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::WifiNetDevice/Phy/State/Tx";
-  Config::ConnectWithoutContext (oss.str (), MakeBoundCallback (&PcapPhyTxEvent, pcap));
-  oss.str ("");
-  oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::WifiNetDevice/Phy/State/RxOk";
-  Config::ConnectWithoutContext (oss.str (), MakeBoundCallback (&PcapPhyRxEvent, pcap));
+  oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::WifiNetDevice/Phy/PromiscSniffer";
+  Config::ConnectWithoutContext (oss.str (), MakeBoundCallback (&PcapSnifferEvent, pcap));
 }
 void 
 YansWifiPhyHelper::EnablePcap (std::string filename, NetDeviceContainer d)