added support for radiotap and prism headers
authorNicola Baldo <nbaldo@cttc.es>
Wed, 03 Jun 2009 11:53:26 +0200
changeset 4492 3ebeb7bf3c15
parent 4491 893d48fcf7f3
child 4494 c5e4af609e21
added support for radiotap and prism headers
CHANGES.html
RELEASE_NOTES
examples/mixed-wireless.cc
examples/simple-wifi-frame-aggregation.cc
examples/third.cc
examples/wifi-wired-bridging.cc
src/common/pcap-writer.cc
src/common/pcap-writer.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/yans-wifi-helper.cc
src/helper/yans-wifi-helper.h
--- a/CHANGES.html	Wed Jun 03 10:04:51 2009 +0200
+++ b/CHANGES.html	Wed Jun 03 11:53:26 2009 +0200
@@ -51,7 +51,16 @@
 </ul>
 
 <h2>New API:</h2>
+
 <ul>
+<li><b>YansWifiPhyHelper supporting radiotap and prism PCAP output</b>
+<p>The newly supported pcap formats can be adopted by calling the following new method of YansWifiPhyHelper:</p>
+<pre>
+ +  void SetPcapFormat (enum PcapFormat format);
+</pre>
+where format is one of PCAP_FORMAT_80211_RADIOTAP, PCAP_FORMAT_80211_PRISM or  PCAP_FORMAT_80211. By default, PCAP_FORMAT_80211 is used, so the default PCAP format is the same as before.</p>
+</li>
+
 <li> <b>attributes for class Ipv4</b>
 <p> class Ipv4 now contains attributes in ipv4.cc; the first one
 is called "IpForward" that will enable/disable Ipv4 forwarding.  
@@ -61,6 +70,44 @@
 <h2>Changes to existing API:</h2>
 <ul>
 
+<p><b>YansWifiPhyHelper::EnablePcap* methods not static any more</b>
+<p>To accommodate the possibility of configuring the PCAP format used for wifi promiscuous mode traces, several methods of YansWifiPhyHelper had to be made non-static:
+<pre>
+-  static void EnablePcap (std::string filename, uint32_t nodeid, uint32_t deviceid);
++         void EnablePcap (std::string filename, uint32_t nodeid, uint32_t deviceid);
+-  static void EnablePcap (std::string filename, Ptr<NetDevice> nd);
++         void EnablePcap (std::string filename, Ptr<NetDevice> nd);
+-  static void EnablePcap (std::string filename, std::string ndName);
++         void EnablePcap (std::string filename, std::string ndName);
+-  static void EnablePcap (std::string filename, NetDeviceContainer d);
++         void EnablePcap (std::string filename, NetDeviceContainer d);
+-  static void EnablePcap (std::string filename, NodeContainer n);
++         void EnablePcap (std::string filename, NodeContainer n);
+-  static void EnablePcapAll (std::string filename);
++         void EnablePcapAll (std::string filename);
+</pre>
+</p>
+</li>
+
+<li><b>Wifi Promisc Sniff interface modified </b>
+<p> 
+To accommodate support for the radiotap and prism headers in PCAP traces, the interface for promiscuos mode sniff in the wifi device was changed. The new implementation was heavily inspired by the way the madwifi driver handles monitor mode. A distinction between TX and RX events is introduced, to account for the fact that different information is to be put in the radiotap/prism header (e.g., RSSI and noise make sense only for RX packets). The following are the relevant modifications to the WifiPhy class:
+<pre>
+-  void NotifyPromiscSniff (Ptr<const Packet> packet);
++  void NotifyPromiscSniffRx (Ptr<const Packet> packet, uint16_t channelFreqMhz, uint32_t rate, bool isShortPreamble, double signalDbm, double noiseDbm);
++  void NotifyPromiscSniffTx (Ptr<const Packet> packet, uint16_t channelFreqMhz, uint32_t rate, bool isShortPreamble);
+-  TracedCallback<Ptr<const Packet> > m_phyPromiscSnifferTrace;
++  TracedCallback<Ptr<const Packet>, uint16_t, uint32_t, bool, double, double> m_phyPromiscSniffRxTrace;
++  TracedCallback<Ptr<const Packet>, uint16_t, uint32_t, bool> m_phyPromiscSniffTxTrace;
+</pre>
+The above mentioned callbacks are expected to be used to call the following method to write Wifi PCAP traces in promiscuous mode:
+<pre>
++  void WriteWifiMonitorPacket(Ptr<const Packet> packet, uint16_t channelFreqMhz, uint32_t rate, bool isShortPreamble, bool isTx, double signalDbm, double noiseDbm);
+</pre>
+In the above method, the isTx parameter is to be used to differentiate between TX and RX packets. For an example of how to implement these callbacks, see the implementation of PcapSniffTxEvent and PcapSniffRxEvent in src/helper/yans-wifi-helper.cc
+</p>
+</li>
+
 <li><b> Routing decoupled from class Ipv4</b>
 <p> All calls of the form "Ipv4::AddHostRouteTo ()" etc. (i.e. to 
 add static routes, both unicast and multicast) have been moved to a new 
--- a/RELEASE_NOTES	Wed Jun 03 10:04:51 2009 +0200
+++ b/RELEASE_NOTES	Wed Jun 03 11:53:26 2009 +0200
@@ -25,6 +25,7 @@
   b) 802.11 PHY:
      - 802.11b PHY support (Gary Pei)
      - Nakagami propagation loss model (Timo Bingmann)
+     - radiotap and prism headers for PCAP output (Nicola Baldo)
   c) GammaVariable and ErlangVariable (Timo Bingmann)
  
 API changes from ns-3.4
--- a/examples/mixed-wireless.cc	Wed Jun 03 10:04:51 2009 +0200
+++ b/examples/mixed-wireless.cc	Wed Jun 03 11:53:26 2009 +0200
@@ -392,9 +392,9 @@
       // Let's do a pcap trace on the application source and sink, ifIndex 0
       // Csma captures in non-promiscuous mode
       CsmaHelper::EnablePcap ("mixed-wireless", appSource->GetId (), 0, false);
-      YansWifiPhyHelper::EnablePcap ("mixed-wireless", appSink->GetId (), 0);
-      YansWifiPhyHelper::EnablePcap ("mixed-wireless", 9, 2);
-      YansWifiPhyHelper::EnablePcap ("mixed-wireless", 9, 0);
+      wifiPhy.EnablePcap ("mixed-wireless", appSink->GetId (), 0);
+      wifiPhy.EnablePcap ("mixed-wireless", 9, 2);
+      wifiPhy.EnablePcap ("mixed-wireless", 9, 0);
     }
 
   if (useCourseChangeCallback == true)
--- a/examples/simple-wifi-frame-aggregation.cc	Wed Jun 03 10:04:51 2009 +0200
+++ b/examples/simple-wifi-frame-aggregation.cc	Wed Jun 03 11:53:26 2009 +0200
@@ -141,7 +141,7 @@
 
   Simulator::Stop (Seconds (10.0));
   
-  YansWifiPhyHelper::EnablePcap ("test-802.11n", 
+  phy.EnablePcap ("test-802.11n", 
     wifiNodes.Get (nWifi - 1)->GetId (), 0);
 
   Simulator::Run ();
--- a/examples/third.cc	Wed Jun 03 10:04:51 2009 +0200
+++ b/examples/third.cc	Wed Jun 03 11:53:26 2009 +0200
@@ -164,7 +164,7 @@
   Simulator::Stop (Seconds (10.0));
 
   PointToPointHelper::EnablePcapAll ("third");
-  YansWifiPhyHelper::EnablePcap ("third", apDevices.Get (0));
+  phy.EnablePcap ("third", apDevices.Get (0));
   CsmaHelper::EnablePcap ("third", csmaDevices.Get (0), true);
 
   Simulator::Run ();
--- a/examples/wifi-wired-bridging.cc	Wed Jun 03 10:04:51 2009 +0200
+++ b/examples/wifi-wired-bridging.cc	Wed Jun 03 11:53:26 2009 +0200
@@ -89,6 +89,10 @@
   backboneDevices = csma.Install (backboneNodes);
 
   double wifiX = 0.0;
+
+  YansWifiPhyHelper wifiPhy = YansWifiPhyHelper::Default ();
+  wifiPhy.SetPcapFormat(YansWifiPhyHelper::PCAP_FORMAT_80211_RADIOTAP);
+
   for (uint32_t i = 0; i < nWifis; ++i)
     {
       // calculate ssid for wifi subnetwork
@@ -105,7 +109,6 @@
       BridgeHelper bridge;
       WifiHelper wifi = WifiHelper::Default ();
       NqosWifiMacHelper wifiMac = NqosWifiMacHelper::Default ();
-      YansWifiPhyHelper wifiPhy = YansWifiPhyHelper::Default ();
       YansWifiChannelHelper wifiChannel = YansWifiChannelHelper::Default ();
       wifiPhy.SetChannel (wifiChannel.Create ());
 
@@ -182,8 +185,8 @@
   apps.Start (Seconds (0.5));
   apps.Stop (Seconds (3.0));
   
-  YansWifiPhyHelper::EnablePcap ("wifi-wired-bridging", apDevices[0]);
-  YansWifiPhyHelper::EnablePcap ("wifi-wired-bridging", apDevices[1]);
+  wifiPhy.EnablePcap ("wifi-wired-bridging", apDevices[0]);
+  wifiPhy.EnablePcap ("wifi-wired-bridging", apDevices[1]);
 
   std::ofstream os;
   os.open ("wifi-wired-bridging.mob");
--- a/src/common/pcap-writer.cc	Wed Jun 03 10:04:51 2009 +0200
+++ b/src/common/pcap-writer.cc	Wed Jun 03 11:53:26 2009 +0200
@@ -41,6 +41,8 @@
   PCAP_PPP      = 9,
   PCAP_RAW_IP   = 101,
   PCAP_80211    = 105,
+  PCAP_80211_PRISM = 119,
+  PCAP_80211_RADIOTAP  = 127,
 };
 
 PcapWriter::PcapWriter ()
@@ -115,6 +117,20 @@
   WriteHeader (PCAP_80211);
 }
 
+void
+PcapWriter::WriteWifiRadiotapHeader (void)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  WriteHeader (PCAP_80211_RADIOTAP);
+}
+
+void
+PcapWriter::WriteWifiPrismHeader (void)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  WriteHeader (PCAP_80211_PRISM);
+}
+
 void 
 PcapWriter::WritePppHeader (void)
 {
@@ -133,6 +149,7 @@
   Write32 (0);
   Write32 (0xffff);
   Write32 (network);
+  m_pcapMode = network;
 }
 
 void 
@@ -151,12 +168,296 @@
     }
 }
 
+
+void PcapWriter::WriteWifiMonitorPacket(Ptr<const Packet> packet, uint16_t channelFreqMhz, uint32_t rate, bool isShortPreamble, bool isTx, double signalDbm, double noiseDbm)
+{  
+  NS_LOG_FUNCTION (this << packet->GetSize() << channelFreqMhz << rate << isShortPreamble << isTx << signalDbm << noiseDbm);
+
+  if (m_writer == 0) 
+    {
+      return;
+    }
+
+  if (m_pcapMode == PCAP_80211)
+    {
+      WritePacket (packet);    
+      return;
+    }
+  
+  /* the following is common between PRISM and RADIOTAP */
+  
+  uint64_t current = Simulator::Now ().GetMicroSeconds ();
+  uint64_t s = current / 1000000;
+  uint64_t us = current % 1000000;
+  Write32 (s & 0xffffffff);
+  Write32 (us & 0xffffffff);
+    
+
+  // MAC timestamp. Actually according to radiotap specifications
+  // (http://www.radiotap.org/defined-fields/TSFT) this should be
+  // the time "when the first bit of the MPDU arrived at the
+  // MAC". This is not exactly what we're doing here, but to handle
+  // this properly we would need to first of all investigate how
+  // real devices (e.g. madwifi) handle this case, especially for TX
+  // packets (radiotap specs says TSFT is not used for TX packets,
+  // but madwifi actually uses it).
+  uint64_t tsft = current;      
+    
+  if (m_pcapMode == PCAP_80211_PRISM)
+    {
+      
+#define PRISM_MSG_CODE		 0x00000044
+#define PRISM_MSG_LENGTH         144
+#define PRISM_DID_HOSTTIME	 0x00010044
+#define PRISM_DID_MACTIME	 0x00020044
+#define PRISM_DID_CHANNEL	 0x00030044
+#define PRISM_DID_RSSI	         0x00040044
+#define PRISM_DID_SQ		 0x00050044
+#define PRISM_DID_SIGNAL	 0x00060044
+#define PRISM_DID_NOISE	         0x00070044
+#define PRISM_DID_RATE	         0x00080044
+#define PRISM_DID_ISTX	         0x00090044
+#define PRISM_DID_FRMLEN	 0x000A0044
+
+#define PRISM_STATUS_PRESENT    0
+#define PRISM_STATUS_ABSENT     1
+#define PRISM_ITEM_LENGTH       4
+
+
+
+      uint32_t size = packet->GetSize () + PRISM_MSG_LENGTH;
+      Write32 (size); // total packet size
+      Write32 (size); // captured size
+
+      Write32(PRISM_MSG_CODE);
+      Write32(PRISM_MSG_LENGTH);
+      WriteData((const uint8_t *)"unknown wifi device!!!!!!!!", 16);
+    
+      Write32(PRISM_DID_HOSTTIME);
+      Write16(PRISM_STATUS_PRESENT);
+      Write16(PRISM_ITEM_LENGTH); 
+      // madwifi reports hosttime in jiffies. 
+      // We calculate jiffies assuming HZ = 10
+      Write32((uint32_t) (Now ().GetMilliSeconds () / 10 ) ); 
+
+      Write32(PRISM_DID_MACTIME);
+      Write16(PRISM_STATUS_PRESENT);
+      Write16(PRISM_ITEM_LENGTH); 
+      // This looses precision, which is a well-known issue of the prism
+      // header format.
+      Write32((uint32_t) tsft);
+
+      Write32(PRISM_DID_CHANNEL);
+      Write16(PRISM_STATUS_PRESENT);
+      Write16(PRISM_ITEM_LENGTH); 
+      // convert from frequency to channel number. This conversion is
+      // correct only for IEEE 802.11b/g channels 1-13.
+      Write32((channelFreqMhz - 2407) / 5);
+
+      Write32(PRISM_DID_RSSI);
+      Write16(PRISM_STATUS_PRESENT);
+      Write16(PRISM_ITEM_LENGTH); 
+      // madwifi here reports a value which is said to be "the value in
+      // dBm above noise". Apart from the fact that this is incorrect
+      // (if it is relative to a value in dBm, then it must be in dB,
+      // not in dBm again), this means that in fact it is not a RSSI
+      // (which stands for Received Signal Strength Indicator) but it is
+      // rather a Signal to Noise Ratio (SNR), of course in dB.
+      // Anyway, in the end we calculate the value exactly as madwifi does.
+      Write32(round(signalDbm - noiseDbm));
+
+      // SQ field not used. I would expect a PRISM_STATUS_ABSENT to be
+      // needed here, but if you look at the prism header that madwifi
+      // produces you'll just see that the whole field structure is
+      // zeroed. 
+      Write32(0);
+      Write16(0);
+      Write16(0); 
+      Write32(0);
+
+      Write32(PRISM_DID_SIGNAL);
+      Write16(PRISM_STATUS_PRESENT);
+      Write16(PRISM_ITEM_LENGTH); 
+      Write32(round(signalDbm));
+
+      Write32(PRISM_DID_NOISE);
+      Write16(PRISM_STATUS_PRESENT);
+      Write16(PRISM_ITEM_LENGTH); 
+      Write32(round(noiseDbm));
+            
+      Write32(PRISM_DID_RATE);    
+      Write16(PRISM_STATUS_PRESENT);
+      Write16(PRISM_ITEM_LENGTH); 
+      Write32(rate);
+ 
+      Write32(PRISM_DID_ISTX);
+      Write16(PRISM_STATUS_PRESENT);
+      Write16(PRISM_ITEM_LENGTH); 
+      Write32(isTx ? 1 : 0);
+
+      Write32(PRISM_DID_FRMLEN);
+      Write16(PRISM_STATUS_ABSENT);
+      Write16(PRISM_ITEM_LENGTH); 
+      Write32(packet->GetSize ());    
+      
+    
+
+    } // PCAP_80211_PRISM
+
+  else if (m_pcapMode == PCAP_80211_RADIOTAP)
+    {      
+      NS_LOG_LOGIC("writing radiotap packet");
+      
+#define	RADIOTAP_TSFT               0x00000001
+#define	RADIOTAP_FLAGS              0x00000002
+#define	RADIOTAP_RATE               0x00000004
+#define RADIOTAP_CHANNEL            0x00000008
+#define	RADIOTAP_FHSS               0x00000010
+#define RADIOTAP_DBM_ANTSIGNAL      0x00000020
+#define RADIOTAP_DBM_ANTNOISE       0x00000040
+#define RADIOTAP_LOCK_QUALITY       0x00000080
+#define RADIOTAP_TX_ATTENUATION     0x00000100    
+#define RADIOTAP_DB_TX_ATTENUATION  0x00000200
+#define RADIOTAP_DBM_TX_POWER       0x00000200
+#define RADIOTAP_ANTENNA            0x00000400
+#define RADIOTAP_DB_ANTSIGNAL       0x00000800
+#define RADIOTAP_DB_ANTNOISE        0x00001000
+#define RADIOTAP_EXT                0x10000000
+
+#define	RADIOTAP_FLAG_NONE	   0x00	
+#define	RADIOTAP_FLAG_CFP	   0x01	
+#define	RADIOTAP_FLAG_SHORTPRE	   0x02	
+#define	RADIOTAP_FLAG_WEP	   0x04	
+#define	RADIOTAP_FLAG_FRAG	   0x08	
+#define	RADIOTAP_FLAG_FCS	   0x10	
+#define	RADIOTAP_FLAG_DATAPAD	   0x20	
+#define	RADIOTAP_FLAG_BADFCS	   0x40	
+
+#define	RADIOTAP_CHANNEL_TURBO	  0x0010
+#define	RADIOTAP_CHANNEL_CCK	  0x0020
+#define	RADIOTAP_CHANNEL_OFDM	  0x0040
+#define	RADIOTAP_CHANNEL_2GHZ	  0x0080
+#define	RADIOTAP_CHANNEL_5GHZ	  0x0100
+#define	RADIOTAP_CHANNEL_PASSIVE  0x0200
+#define	RADIOTAP_CHANNEL_DYN	  0x0400
+#define	RADIOTAP_CHANNEL_GFSK	  0x0800
+
+#define RADIOTAP_RX_PRESENT (RADIOTAP_TSFT | RADIOTAP_FLAGS | RADIOTAP_RATE | RADIOTAP_CHANNEL | RADIOTAP_DBM_ANTSIGNAL | RADIOTAP_DBM_ANTNOISE)
+#define RADIOTAP_RX_LENGTH (8+8+1+1+2+2+1+1)
+
+#define RADIOTAP_TX_PRESENT (RADIOTAP_TSFT | RADIOTAP_FLAGS  | RADIOTAP_RATE | RADIOTAP_CHANNEL)
+#define RADIOTAP_TX_LENGTH (8+8+1+1+2+2)
+
+      uint32_t size;
+      if (isTx)
+        {
+          size = packet->GetSize () + RADIOTAP_TX_LENGTH;
+        }
+      else
+        {
+          size = packet->GetSize () + RADIOTAP_RX_LENGTH;
+        }
+      Write32 (size); // total packet size
+      Write32 (size); // captured size
+
+      Write8(0); // radiotap version
+      Write8(0); // padding
+
+      if (isTx)
+        {
+          Write16(RADIOTAP_TX_LENGTH); 
+          Write32(RADIOTAP_TX_PRESENT); 
+        }
+      else
+        {
+          Write16(RADIOTAP_RX_LENGTH); 
+          Write32(RADIOTAP_RX_PRESENT); 
+        }
+
+      Write64(tsft); 
+      
+      uint8_t flags = RADIOTAP_FLAG_NONE;
+      if (isShortPreamble)
+        {
+          flags |= RADIOTAP_FLAG_SHORTPRE; 
+        }
+      Write8(flags);
+      
+
+      Write8(rate); 
+
+      Write16((uint16_t) channelFreqMhz); 
+
+      // we might want to make this setting depend on the WifiMode and
+      // on the ChannelFrequency at some time in the future. But for now
+      // I think a fixed setting is more than enough for most purposes.
+      Write16(RADIOTAP_CHANNEL_OFDM | RADIOTAP_CHANNEL_2GHZ); 
+    
+      if (!isTx)
+        {
+          
+          Write8 (RoundToInt8 (signalDbm)); 
+          Write8 (RoundToInt8 (noiseDbm)); 
+        }
+
+    } // PCAP_80211_RADIOTAP
+
+    
+  else
+    {
+      NS_LOG_ERROR("unknown PCAP mode");      
+      return;
+    }    
+
+  // finally, write rest of packet
+  WriteData (packet->PeekData (), packet->GetSize ());
+}
+    
+  
+
+
+int8_t 
+PcapWriter::RoundToInt8 (double value)
+{
+  if (value < -128)
+    {
+      return -128;
+    }
+  if (value > 127)
+    {
+      return 127;
+    }
+  return ((int8_t) round(value));
+}
+
+
+
+
+
+
 void
 PcapWriter::WriteData (uint8_t const*buffer, uint32_t size)
 {
+  NS_LOG_FUNCTION(this << size);
   m_writer->write ((char const *)buffer, size);
 }
 
+
+void
+PcapWriter::Write64 (uint64_t data)
+{
+  uint8_t buffer[8];
+  buffer[0] = (data >> 0) & 0xff;
+  buffer[1] = (data >> 8) & 0xff;
+  buffer[2] = (data >> 16) & 0xff;
+  buffer[3] = (data >> 24) & 0xff;
+  buffer[4] = (data >> 32) & 0xff;
+  buffer[5] = (data >> 40) & 0xff;
+  buffer[6] = (data >> 48) & 0xff;
+  buffer[7] = (data >> 56) & 0xff;
+  WriteData (buffer, 8);
+}
+
 void
 PcapWriter::Write32 (uint32_t data)
 {
@@ -177,4 +478,12 @@
   WriteData (buffer, 2);
 }
 
+void
+PcapWriter::Write8 (uint8_t data)
+{
+  WriteData (&data, 1);
+}
+
+
+
 } // namespace ns3
--- a/src/common/pcap-writer.h	Wed Jun 03 10:04:51 2009 +0200
+++ b/src/common/pcap-writer.h	Wed Jun 03 11:53:26 2009 +0200
@@ -76,6 +76,24 @@
 
   /**
    * Write a pcap header in the output file which specifies
+   * that the content of the file will be 802.11 Packets preceded by a
+   * radiotap header providing PHY layer info. This method should be
+   * invoked before ns3::PcapWriter::WritePacket and after
+   * ns3::PcapWriter::Open. 
+   */
+  void WriteWifiRadiotapHeader (void);
+
+  /**
+   * Write a pcap header in the output file which specifies
+   * that the content of the file will be 802.11 Packets preceded by a
+   * prism header providing PHY layer info. This method should be
+   * invoked before ns3::PcapWriter::WritePacket and after
+   * ns3::PcapWriter::Open. 
+   */
+  void WriteWifiPrismHeader (void);
+
+  /**
+   * Write a pcap header in the output file which specifies
    * that the content of the file will be ppp Packets. This 
    * method should be invoked before ns3::PcapWriter::WritePacket 
    * and after ns3::PcapWriter::Open.
@@ -87,12 +105,40 @@
    */
   void WritePacket (Ptr<const Packet> packet);
 
+  /** 
+   * Write a Packet, possibly adding wifi PHY layer information to it
+   *
+   * @param packet the packet being received
+   * @param channelFreqMhz the frequency in MHz at which the packet is
+   * received. Note that in real devices this is normally the
+   * frequency to which  the receiver is tuned, and this can be
+   * different than the frequency at which the packet was originally
+   * transmitted. This is because it is possible to have the receiver
+   * tuned on a given channel and still to be able to receive packets
+   * on a nearby channel.
+   * @param rate the PHY data rate in units of 500kbps (i.e., the same
+   * units used both for the radiotap and for the prism header) 
+   * @param isPreambleShort true if short preamble is used, false otherwise
+   * @param isTx true if packet is being transmitted, false when
+   * packet is being received
+   * @param signalDbm signal power in dBm
+   * @param noiseDbm  noise power in dBm
+   */
+  void WriteWifiMonitorPacket(Ptr<const Packet> packet, uint16_t channelFreqMhz, uint32_t rate, bool isShortPreamble, bool isTx, double signalDbm, double noiseDbm);
+
+
+
+
 private:
   void WriteData (uint8_t const*buffer, uint32_t size);
+  void Write64 (uint64_t data);
   void Write32 (uint32_t data);
   void Write16 (uint16_t data);
+  void Write8 (uint8_t data);
   void WriteHeader (uint32_t network);
+  int8_t RoundToInt8 (double value);
   std::ofstream *m_writer;
+  uint32_t m_pcapMode;
 };
 
 } // namespace ns3
--- a/src/devices/wifi/wifi-phy.cc	Wed Jun 03 10:04:51 2009 +0200
+++ b/src/devices/wifi/wifi-phy.cc	Wed Jun 03 11:53:26 2009 +0200
@@ -73,9 +73,12 @@
     .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_phyPromiscSnifferTrace))
+    .AddTraceSource ("PromiscSnifferRx", 
+                     "Trace source simulating a wifi device in monitor mode sniffing all received frames",
+                     MakeTraceSourceAccessor (&WifiPhy::m_phyPromiscSniffRxTrace))
+    .AddTraceSource ("PromiscSnifferTx", 
+                     "Trace source simulating the capability of a wifi device in monitor mode to sniff all frames being transmitted",
+                     MakeTraceSourceAccessor (&WifiPhy::m_phyPromiscSniffTxTrace))
     ;
   return tid;
 }
@@ -194,9 +197,15 @@
 }
 
 void 
-WifiPhy::NotifyPromiscSniff (Ptr<const Packet> packet) 
+WifiPhy::NotifyPromiscSniffRx (Ptr<const Packet> packet, uint16_t channelFreqMhz, uint32_t rate, bool isShortPreamble, double signalDbm, double noiseDbm)
 {
-  m_phyPromiscSnifferTrace (packet);
+  m_phyPromiscSniffRxTrace (packet, channelFreqMhz, rate, isShortPreamble, signalDbm, noiseDbm);
+}
+
+void 
+WifiPhy::NotifyPromiscSniffTx (Ptr<const Packet> packet, uint16_t channelFreqMhz, uint32_t rate, bool isShortPreamble)
+{
+  m_phyPromiscSniffTxTrace (packet, channelFreqMhz, rate, isShortPreamble);
 }
 
 WifiMode 
--- a/src/devices/wifi/wifi-phy.h	Wed Jun 03 10:04:51 2009 +0200
+++ b/src/devices/wifi/wifi-phy.h	Wed Jun 03 11:53:26 2009 +0200
@@ -294,11 +294,46 @@
    */
   void NotifyRxDrop (Ptr<const Packet> packet);
 
-  /**
-   * Public method used to fire a PromiscSniffer trace.  Implemented for encapsulation 
+  /** 
+   * 
+   * Public method used to fire a PromiscSniffer trace for a wifi packet being received.  Implemented for encapsulation 
    * purposes.
+   * 
+   * @param packet the packet being received
+   * @param channelFreqMhz the frequency in MHz at which the packet is
+   * received. Note that in real devices this is normally the
+   * frequency to which  the receiver is tuned, and this can be
+   * different than the frequency at which the packet was originally
+   * transmitted. This is because it is possible to have the receiver
+   * tuned on a given channel and still to be able to receive packets
+   * on a nearby channel.
+   * @param rate the PHY data rate in units of 500kbps (i.e., the same
+   * units used both for the radiotap and for the prism header) 
+   * @param isPreambleShort true if short preamble is used, false otherwise
+   * @param signalDbm signal power in dBm
+   * @param noiseDbm  noise power in dBm
    */
-  void NotifyPromiscSniff (Ptr<const Packet> packet);
+  void NotifyPromiscSniffRx (Ptr<const Packet> packet, uint16_t channelFreqMhz, uint32_t rate, bool isShortPreamble, double signalDbm, double noiseDbm);
+
+  /** 
+   * 
+   * Public method used to fire a PromiscSniffer trace for a wifi packet being transmitted.  Implemented for encapsulation 
+   * purposes.
+   * 
+   * @param packet the packet being received
+   * @param channelFreqMhz the frequency in MHz at which the packet is
+   * received. Note that in real devices this is normally the
+   * frequency to which  the receiver is tuned, and this can be
+   * different than the frequency at which the packet was originally
+   * transmitted. This is because it is possible to have the receiver
+   * tuned on a given channel and still to be able to receive packets
+   * on a nearby channel.
+   * @param rate the PHY data rate in units of 500kbps (i.e., the same
+   * units used both for the radiotap and for the prism header) 
+   * @param isPreambleShort true if short preamble is used, false otherwise
+   */
+  void NotifyPromiscSniffTx (Ptr<const Packet> packet, uint16_t channelFreqMhz, uint32_t rate, bool isShortPreamble);
+  
 
 private:
   /**
@@ -349,24 +384,29 @@
   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.
+   * A trace source that emulates a wifi device in monitor mode
+   * sniffing a packet being received. 
+   * 
+   * As a reference with the real world, firing this trace
+   * corresponds in the madwifi driver to calling the function
+   * ieee80211_input_monitor()
    *
    * \see class CallBackTraceSource
    */
-  TracedCallback<Ptr<const Packet> > m_phyPromiscSnifferTrace;
+  TracedCallback<Ptr<const Packet>, uint16_t, uint32_t, bool, double, double> m_phyPromiscSniffRxTrace;
+
+  /**
+   * A trace source that emulates a wifi device in monitor mode
+   * sniffing a packet being transmitted. 
+   * 
+   * As a reference with the real world, firing this trace
+   * corresponds in the madwifi driver to calling the function
+   * ieee80211_input_monitor()
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet>, uint16_t, uint32_t, bool> m_phyPromiscSniffTxTrace;
+
 };
 
 } // namespace ns3
--- a/src/devices/wifi/yans-wifi-phy.cc	Wed Jun 03 10:04:51 2009 +0200
+++ b/src/devices/wifi/yans-wifi-phy.cc	Wed Jun 03 11:53:26 2009 +0200
@@ -121,8 +121,10 @@
 }
 
 YansWifiPhy::YansWifiPhy ()
- : m_endSyncEvent (),
-   m_random (0.0, 1.0)
+  :  m_channelFreqMhz(2437),
+     m_endSyncEvent (),
+     m_random (0.0, 1.0)
+
 {
   NS_LOG_FUNCTION (this);
   m_state = CreateObject<WifiPhyStateHelper> ();
@@ -408,7 +410,9 @@
       m_endSyncEvent.Cancel ();
     }
   NotifyTxBegin (packet);
-  NotifyPromiscSniff (packet);
+  uint32_t dataRate500KbpsUnits = txMode.GetDataRate () / 500000;   
+  bool isShortPreamble = (WIFI_PREAMBLE_SHORT == preamble);
+  NotifyPromiscSniffTx (packet, m_channelFreqMhz, dataRate500KbpsUnits, isShortPreamble);
   m_state->SwitchToTx (txDuration, packet, txMode, preamble, txPower);
   m_channel->Send (this, packet, GetPowerDbm (txPower) + m_txGainDb, txMode, preamble);
 }
@@ -577,11 +581,14 @@
 
   NS_LOG_DEBUG ("mode="<<(event->GetPayloadMode ().GetDataRate ())<<
                 ", snr="<<snrPer.snr<<", per="<<snrPer.per<<", size="<<packet->GetSize ());
-  
   if (m_random.GetValue () > snrPer.per) 
     {
-      NotifyRxEnd (packet);
-      NotifyPromiscSniff (packet);
+      NotifyRxEnd (packet); 
+      uint32_t dataRate500KbpsUnits = event->GetPayloadMode ().GetDataRate () / 500000;   
+      bool isShortPreamble = (WIFI_PREAMBLE_SHORT == event->GetPreambleType ());  
+      double signalDbm = RatioToDb (event->GetRxPowerW ()) + 30;
+      double noiseDbm = RatioToDb(event->GetRxPowerW() / snrPer.snr) - GetRxNoiseFigure() + 30 ;
+      NotifyPromiscSniffRx (packet, m_channelFreqMhz, dataRate500KbpsUnits, isShortPreamble, signalDbm, noiseDbm);
       m_state->SwitchFromSyncEndOk (packet, snrPer.snr, event->GetPayloadMode (), event->GetPreambleType ());
     } 
   else 
@@ -591,5 +598,4 @@
       m_state->SwitchFromSyncEndError (packet, snrPer.snr);
     }
 }
-
 } // namespace ns3
--- a/src/devices/wifi/yans-wifi-phy.h	Wed Jun 03 10:04:51 2009 +0200
+++ b/src/devices/wifi/yans-wifi-phy.h	Wed Jun 03 11:53:26 2009 +0200
@@ -142,6 +142,7 @@
   double   m_txPowerBaseDbm;
   double   m_txPowerEndDbm;
   uint32_t m_nTxPower;
+  uint16_t m_channelFreqMhz;
 
   Ptr<YansWifiChannel> m_channel;
   Ptr<Object> m_device;
--- a/src/helper/yans-wifi-helper.cc	Wed Jun 03 10:04:51 2009 +0200
+++ b/src/helper/yans-wifi-helper.cc	Wed Jun 03 11:53:26 2009 +0200
@@ -31,11 +31,19 @@
 
 namespace ns3 {
 
-static void PcapSnifferEvent (Ptr<PcapWriter> writer, Ptr<const Packet> packet)
+static void PcapSniffTxEvent (Ptr<PcapWriter> writer, Ptr<const Packet> packet, uint16_t channelFreqMhz,  uint32_t rate, bool isShortPreamble)
 {
-  writer->WritePacket (packet);
+  const double unusedValue = 0;
+  writer->WriteWifiMonitorPacket(packet, channelFreqMhz, rate, isShortPreamble, true, unusedValue, unusedValue); 
 }
 
+
+static void PcapSniffRxEvent (Ptr<PcapWriter> writer, Ptr<const Packet> packet, uint16_t channelFreqMhz,  uint32_t rate, bool isShortPreamble, double signalDbm, double noiseDbm)
+{
+  writer->WriteWifiMonitorPacket(packet, channelFreqMhz, rate, isShortPreamble, false, signalDbm, noiseDbm); 
+}
+
+
 static void AsciiPhyTxEvent (std::ostream *os, std::string context, 
                              Ptr<const Packet> packet,
                              WifiMode mode, WifiPreamble preamble, 
@@ -137,7 +145,9 @@
 
 
 YansWifiPhyHelper::YansWifiPhyHelper ()
-  : m_channel (0)
+  : m_channel (0),
+    m_pcapFormat(PCAP_FORMAT_80211)
+    
 {
   m_phy.SetTypeId ("ns3::YansWifiPhy");
 }
@@ -202,6 +212,14 @@
   return phy;
 }
 
+
+void 
+YansWifiPhyHelper::SetPcapFormat (enum PcapFormat format)
+{
+  m_pcapFormat = format;
+}
+
+
 void 
 YansWifiPhyHelper::EnablePcap (std::string filename, uint32_t nodeid, uint32_t deviceid)
 {
@@ -218,11 +236,28 @@
   // with the locally-defined WifiPhyHelper::Create method.
   Ptr<PcapWriter> pcap = ::ns3::Create<PcapWriter> ();
   pcap->Open (oss.str ());
-  pcap->WriteWifiHeader ();
+
+  switch (m_pcapFormat) {
+  case PCAP_FORMAT_80211:
+    pcap->WriteWifiHeader ();  
+    break;
+  case PCAP_FORMAT_80211_RADIOTAP:
+    pcap->WriteWifiRadiotapHeader ();  
+    break;
+  case PCAP_FORMAT_80211_PRISM:
+    pcap->WriteWifiPrismHeader ();  
+    break;
+  }
+  
   oss.str ("");
   oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid;
-  oss << "/$ns3::WifiNetDevice/Phy/PromiscSniffer";
-  Config::ConnectWithoutContext (oss.str (), MakeBoundCallback (&PcapSnifferEvent, pcap));
+  oss << "/$ns3::WifiNetDevice/Phy/PromiscSnifferTx";
+  Config::ConnectWithoutContext (oss.str (), MakeBoundCallback (&PcapSniffTxEvent, pcap));
+
+  oss.str ("");
+  oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid;
+  oss << "/$ns3::WifiNetDevice/Phy/PromiscSnifferRx";
+  Config::ConnectWithoutContext (oss.str (), MakeBoundCallback (&PcapSniffRxEvent, pcap));  
 }
 
 void 
--- a/src/helper/yans-wifi-helper.h	Wed Jun 03 10:04:51 2009 +0200
+++ b/src/helper/yans-wifi-helper.h	Wed Jun 03 11:53:26 2009 +0200
@@ -198,18 +198,45 @@
                           std::string n7 = "", const AttributeValue &v7 = EmptyAttributeValue ());
 
   /**
+   * PCAP formats 
+   * 
+   */
+  enum PcapFormat {   
+    PCAP_FORMAT_80211          = 1,
+    PCAP_FORMAT_80211_PRISM    = 2,
+    PCAP_FORMAT_80211_RADIOTAP = 3,
+  };
+  
+  /** 
+   * Set the format of PCAP traces to be used. This function has to be
+   * called before EnablePcap(), so that the header of the pcap file
+   * can be written correctly.
+   *
+   * In madwifi, this corresponds to setting
+   * /proc/sys/net/ath0/dev_type to a particular value. See
+   * http://madwifi-project.org/wiki/UserDocs/MonitorModeInterface for
+   * more information.
+   * 
+   * @param format the PcapFormat to be used
+   */
+  void SetPcapFormat (enum PcapFormat format);
+
+  /**
    * \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.
+   * data is stored in the file prefix-nodeid-deviceid.pcap. By
+   * default, no PHY layer information is provided. An optional header
+   * with PHY layer information, such as the radiotap or the prism
+   * header, can be used by invoking SetPcapFormat().
    *
    * 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);
+  void EnablePcap (std::string filename, uint32_t nodeid, uint32_t deviceid);
 
   /**
    * \param filename filename prefix to use for pcap files.
@@ -218,7 +245,7 @@
    * Enable pcap output on each input device which is of the
    * ns3::WifiNetDevice type.
    */
-  static void EnablePcap (std::string filename, Ptr<NetDevice> nd);
+   void EnablePcap (std::string filename, Ptr<NetDevice> nd);
 
   /**
    * \param filename filename prefix to use for pcap files.
@@ -227,7 +254,7 @@
    * Enable pcap output on each input device which is of the
    * ns3::WifiNetDevice type.
    */
-  static void EnablePcap (std::string filename, std::string ndName);
+   void EnablePcap (std::string filename, std::string ndName);
 
   /**
    * \param filename filename prefix to use for pcap files.
@@ -236,7 +263,7 @@
    * Enable pcap output on each input device which is of the
    * ns3::WifiNetDevice type.
    */
-  static void EnablePcap (std::string filename, NetDeviceContainer d);
+   void EnablePcap (std::string filename, NetDeviceContainer d);
 
   /**
    * \param filename filename prefix to use for pcap files.
@@ -246,7 +273,7 @@
    * ns3::WifiNetDevice type and which is located in one of the 
    * input nodes.
    */
-  static void EnablePcap (std::string filename, NodeContainer n);
+   void EnablePcap (std::string filename, NodeContainer n);
 
   /**
    * \param filename filename prefix to use for pcap files.
@@ -254,7 +281,7 @@
    * Enable pcap output on each device which is of the
    * ns3::WifiNetDevice type
    */
-  static void EnablePcapAll (std::string filename);
+   void EnablePcapAll (std::string filename);
 
   /**
    * \param os output stream
@@ -311,6 +338,7 @@
   ObjectFactory m_phy;
   ObjectFactory m_errorRateModel;
   Ptr<YansWifiChannel> m_channel;
+  enum PcapFormat m_pcapFormat;
 };
 
 } // namespace ns3