src/common/pcap-writer.cc
changeset 4492 3ebeb7bf3c15
parent 4099 03dc74055f8a
child 4498 1b3d01bd974d
--- 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