src/common/pcap-writer.cc
author Nicola Baldo <nbaldo@cttc.es>
Thu Aug 13 09:36:53 2009 +0200 (2009-08-13)
changeset 4709 b0743dbc4e55
parent 4693 ca8cbdd42786
child 4715 d0041768ff60
permissions -rw-r--r--
bug 639: add configurable capture size to pcap
     1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
     2 /*
     3  * Copyright (c) 2005,2006 INRIA
     4  *
     5  * This program is free software; you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License version 2 as
     7  * published by the Free Software Foundation;
     8  *
     9  * This program is distributed in the hope that it will be useful,
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  * GNU General Public License for more details.
    13  *
    14  * You should have received a copy of the GNU General Public License
    15  * along with this program; if not, write to the Free Software
    16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    17  *
    18  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
    19  */
    20 
    21 /*
    22  * Documentation kindly pointed out by Tom Henderson:
    23  * http://wiki.ethereal.com/Development/LibpcapFileFormat
    24  */
    25 
    26 #include <fstream>
    27 
    28 #include "ns3/log.h"
    29 #include "ns3/assert.h"
    30 #include "ns3/abort.h"
    31 #include "ns3/simulator.h"
    32 #include "ns3/uinteger.h"
    33 #include "pcap-writer.h"
    34 #include "packet.h"
    35 
    36 NS_LOG_COMPONENT_DEFINE ("PcapWriter");
    37 
    38 namespace ns3 {
    39 
    40 NS_OBJECT_ENSURE_REGISTERED (PcapWriter);
    41 
    42 enum {
    43   PCAP_ETHERNET = 1,
    44   PCAP_PPP      = 9,
    45   PCAP_RAW_IP   = 101,
    46   PCAP_80211    = 105,
    47   PCAP_80211_PRISM = 119,
    48   PCAP_80211_RADIOTAP  = 127,
    49 };
    50 
    51 TypeId 
    52 PcapWriter::GetTypeId (void)
    53 {
    54   static TypeId tid = TypeId ("ns3::PcapWriter")
    55     .SetParent<Object> ()
    56     .AddConstructor<PcapWriter> ()
    57     .AddAttribute ("CaptureSize",
    58                    "Number of bytes to capture at the start of each packet written in the pcap file. Zero means capture all bytes.",
    59                    UintegerValue (0),
    60                    MakeUintegerAccessor (&PcapWriter::m_captureSize),
    61                    MakeUintegerChecker<uint32_t> ())
    62     ;
    63   return tid;
    64 }
    65 
    66 PcapWriter::PcapWriter ()
    67 {
    68   NS_LOG_FUNCTION (this);
    69   NS_LOG_LOGIC ("m_writer = 0");
    70   m_writer = 0;
    71 }
    72 
    73 PcapWriter::~PcapWriter ()
    74 {
    75   NS_LOG_FUNCTION (this);
    76 
    77   if (m_writer != 0)
    78     {
    79       NS_LOG_LOGIC ("m_writer nonzero " << m_writer);
    80       if (m_writer->is_open ())
    81         {
    82           NS_LOG_LOGIC ("m_writer open.  Closing " << m_writer);
    83           m_writer->close ();
    84         }
    85 
    86       NS_LOG_LOGIC ("Deleting writer " << m_writer);
    87       delete m_writer;
    88 
    89       NS_LOG_LOGIC ("m_writer = 0");
    90       m_writer = 0;
    91     }
    92   else
    93     {
    94       NS_LOG_LOGIC ("m_writer == 0");
    95     }
    96 }
    97 
    98 void
    99 PcapWriter::Open (std::string const &name)
   100 {
   101   NS_LOG_FUNCTION (this << name);
   102   NS_ABORT_MSG_UNLESS (m_writer == 0, "PcapWriter::Open(): m_writer already allocated (std::ofstream leak detected)");
   103 
   104   m_writer = new std::ofstream ();
   105   NS_ABORT_MSG_UNLESS (m_writer, "PcapWriter::Open(): Cannot allocate m_writer");
   106 
   107   NS_LOG_LOGIC ("Created writer " << m_writer);
   108 
   109   m_writer->open (name.c_str (), std::ios_base::binary | std::ios_base::out);
   110   NS_ABORT_MSG_IF (m_writer->fail (), "PcapWriter::Open(): m_writer->open(" << name.c_str () << ") failed");
   111 
   112   NS_ASSERT_MSG (m_writer->is_open (), "PcapWriter::Open(): m_writer not open");
   113 
   114   NS_LOG_LOGIC ("Writer opened successfully");
   115 }
   116 
   117 void 
   118 PcapWriter::WriteEthernetHeader (void)
   119 {
   120   NS_LOG_FUNCTION_NOARGS ();
   121   WriteHeader (PCAP_ETHERNET);
   122 }
   123 
   124 void 
   125 PcapWriter::WriteIpHeader (void)
   126 {
   127   NS_LOG_FUNCTION_NOARGS ();
   128   WriteHeader (PCAP_RAW_IP);
   129 }
   130 
   131 void
   132 PcapWriter::WriteWifiHeader (void)
   133 {
   134   NS_LOG_FUNCTION_NOARGS ();
   135   WriteHeader (PCAP_80211);
   136 }
   137 
   138 void
   139 PcapWriter::WriteWifiRadiotapHeader (void)
   140 {
   141   NS_LOG_FUNCTION_NOARGS ();
   142   WriteHeader (PCAP_80211_RADIOTAP);
   143 }
   144 
   145 void
   146 PcapWriter::WriteWifiPrismHeader (void)
   147 {
   148   NS_LOG_FUNCTION_NOARGS ();
   149   WriteHeader (PCAP_80211_PRISM);
   150 }
   151 
   152 void 
   153 PcapWriter::WritePppHeader (void)
   154 {
   155   NS_LOG_FUNCTION_NOARGS ();
   156   WriteHeader (PCAP_PPP);
   157 }
   158 
   159 void 
   160 PcapWriter::WriteHeader (uint32_t network)
   161 {
   162   NS_LOG_FUNCTION (this << network);
   163   Write32 (0xa1b2c3d4);
   164   Write16 (2);
   165   Write16 (4);
   166   Write32 (0);
   167   Write32 (0);
   168   Write32 (0xffff);
   169   Write32 (network);
   170   m_pcapMode = network;
   171 }
   172 
   173 void 
   174 PcapWriter::WritePacket (Ptr<const Packet> packet)
   175 {
   176   if (m_writer != 0) 
   177     {
   178       uint64_t current = Simulator::Now ().GetMicroSeconds ();
   179       uint64_t s = current / 1000000;
   180       uint64_t us = current % 1000000;
   181       Write32 (s & 0xffffffff);
   182       Write32 (us & 0xffffffff);
   183       uint32_t thisCaptureSize;
   184       if (m_captureSize == 0)
   185         {
   186           thisCaptureSize = packet->GetSize ();
   187         }
   188       else
   189         {
   190           thisCaptureSize = std::min (m_captureSize, packet->GetSize ());         
   191         }          
   192       Write32 (thisCaptureSize); 
   193       Write32 (packet->GetSize ()); // actual packet size
   194       packet->CopyData (m_writer, thisCaptureSize);
   195     }
   196 }
   197 
   198 
   199 void PcapWriter::WriteWifiMonitorPacket(Ptr<const Packet> packet, uint16_t channelFreqMhz, 
   200                                         uint32_t rate, bool isShortPreamble, bool isTx, 
   201                                         double signalDbm, double noiseDbm)
   202 {  
   203   NS_LOG_FUNCTION (this << packet->GetSize() << channelFreqMhz << rate << isShortPreamble << isTx << signalDbm << noiseDbm);
   204 
   205   if (m_writer == 0) 
   206     {
   207       return;
   208     }
   209 
   210   if (m_pcapMode == PCAP_80211)
   211     {
   212       WritePacket (packet);    
   213       return;
   214     }
   215   
   216   /* the following is common between PRISM and RADIOTAP */
   217   
   218   uint64_t current = Simulator::Now ().GetMicroSeconds ();
   219   uint64_t s = current / 1000000;
   220   uint64_t us = current % 1000000;
   221   Write32 (s & 0xffffffff);
   222   Write32 (us & 0xffffffff);
   223     
   224 
   225   // MAC timestamp. Actually according to radiotap specifications
   226   // (http://www.radiotap.org/defined-fields/TSFT) this should be
   227   // the time "when the first bit of the MPDU arrived at the
   228   // MAC". This is not exactly what we're doing here, but to handle
   229   // this properly we would need to first of all investigate how
   230   // real devices (e.g. madwifi) handle this case, especially for TX
   231   // packets (radiotap specs says TSFT is not used for TX packets,
   232   // but madwifi actually uses it).
   233   uint64_t tsft = current;    
   234 
   235   
   236   uint32_t wifiMonitorHeaderSize;  
   237     
   238   if (m_pcapMode == PCAP_80211_PRISM)
   239     {
   240       
   241 #define PRISM_MSG_CODE		 0x00000044
   242 #define PRISM_MSG_LENGTH         144
   243 #define PRISM_DID_HOSTTIME	 0x00010044
   244 #define PRISM_DID_MACTIME	 0x00020044
   245 #define PRISM_DID_CHANNEL	 0x00030044
   246 #define PRISM_DID_RSSI	         0x00040044
   247 #define PRISM_DID_SQ		 0x00050044
   248 #define PRISM_DID_SIGNAL	 0x00060044
   249 #define PRISM_DID_NOISE	         0x00070044
   250 #define PRISM_DID_RATE	         0x00080044
   251 #define PRISM_DID_ISTX	         0x00090044
   252 #define PRISM_DID_FRMLEN	 0x000A0044
   253 
   254 #define PRISM_STATUS_PRESENT    0
   255 #define PRISM_STATUS_ABSENT     1
   256 #define PRISM_ITEM_LENGTH       4
   257 
   258 
   259       wifiMonitorHeaderSize = PRISM_MSG_LENGTH;
   260       if (m_captureSize == 0)
   261         {
   262           Write32 (packet->GetSize () + wifiMonitorHeaderSize); // captured size == actual packet size
   263         }
   264       else
   265         {
   266           uint32_t thisCaptureSize = std::min (m_captureSize, packet->GetSize () + wifiMonitorHeaderSize);         
   267           Write32 (thisCaptureSize); 
   268         }
   269       Write32 (packet->GetSize () + wifiMonitorHeaderSize); // actual packet size
   270 
   271       Write32(PRISM_MSG_CODE);
   272       Write32(PRISM_MSG_LENGTH);
   273       WriteData((const uint8_t *)"unknown wifi device!!!!!!!!", 16);
   274     
   275       Write32(PRISM_DID_HOSTTIME);
   276       Write16(PRISM_STATUS_PRESENT);
   277       Write16(PRISM_ITEM_LENGTH); 
   278       // madwifi reports hosttime in jiffies. 
   279       // We calculate jiffies assuming HZ = 10
   280       Write32((uint32_t) (Now ().GetMilliSeconds () / 10 ) ); 
   281 
   282       Write32(PRISM_DID_MACTIME);
   283       Write16(PRISM_STATUS_PRESENT);
   284       Write16(PRISM_ITEM_LENGTH); 
   285       // This looses precision, which is a well-known issue of the prism
   286       // header format.
   287       Write32((uint32_t) tsft);
   288 
   289       Write32(PRISM_DID_CHANNEL);
   290       Write16(PRISM_STATUS_PRESENT);
   291       Write16(PRISM_ITEM_LENGTH); 
   292       // convert from frequency to channel number. This conversion is
   293       // correct only for IEEE 802.11b/g channels 1-13.
   294       Write32((2437 - 2407) / 5);
   295 
   296       Write32(PRISM_DID_RSSI);
   297       Write16(PRISM_STATUS_PRESENT);
   298       Write16(PRISM_ITEM_LENGTH); 
   299       // madwifi here reports a value which is said to be "the value in
   300       // dBm above noise". Apart from the fact that this is incorrect
   301       // (if it is relative to a value in dBm, then it must be in dB,
   302       // not in dBm again), this means that in fact it is not a RSSI
   303       // (which stands for Received Signal Strength Indicator) but it is
   304       // rather a Signal to Noise Ratio (SNR), of course in dB.
   305       // Anyway, in the end we calculate the value exactly as madwifi does.
   306       Write32((uint32_t)round(signalDbm - noiseDbm));
   307 
   308       // SQ field not used. I would expect a PRISM_STATUS_ABSENT to be
   309       // needed here, but if you look at the prism header that madwifi
   310       // produces you'll just see that the whole field structure is
   311       // zeroed. 
   312       Write32(0);
   313       Write16(0);
   314       Write16(0); 
   315       Write32(0);
   316 
   317       Write32(PRISM_DID_SIGNAL);
   318       Write16(PRISM_STATUS_PRESENT);
   319       Write16(PRISM_ITEM_LENGTH); 
   320       Write32((uint32_t)round(signalDbm));
   321 
   322       Write32(PRISM_DID_NOISE);
   323       Write16(PRISM_STATUS_PRESENT);
   324       Write16(PRISM_ITEM_LENGTH); 
   325       Write32((uint32_t)round(noiseDbm));
   326             
   327       Write32(PRISM_DID_RATE);    
   328       Write16(PRISM_STATUS_PRESENT);
   329       Write16(PRISM_ITEM_LENGTH); 
   330       Write32(rate);
   331  
   332       Write32(PRISM_DID_ISTX);
   333       Write16(PRISM_STATUS_PRESENT);
   334       Write16(PRISM_ITEM_LENGTH); 
   335       Write32(isTx ? 1 : 0);
   336 
   337       Write32(PRISM_DID_FRMLEN);
   338       Write16(PRISM_STATUS_ABSENT);
   339       Write16(PRISM_ITEM_LENGTH); 
   340       Write32(packet->GetSize ());    
   341       
   342     
   343 
   344     } // PCAP_80211_PRISM
   345 
   346   else if (m_pcapMode == PCAP_80211_RADIOTAP)
   347     {      
   348       NS_LOG_LOGIC("writing radiotap packet");
   349       
   350 #define	RADIOTAP_TSFT               0x00000001
   351 #define	RADIOTAP_FLAGS              0x00000002
   352 #define	RADIOTAP_RATE               0x00000004
   353 #define RADIOTAP_CHANNEL            0x00000008
   354 #define	RADIOTAP_FHSS               0x00000010
   355 #define RADIOTAP_DBM_ANTSIGNAL      0x00000020
   356 #define RADIOTAP_DBM_ANTNOISE       0x00000040
   357 #define RADIOTAP_LOCK_QUALITY       0x00000080
   358 #define RADIOTAP_TX_ATTENUATION     0x00000100    
   359 #define RADIOTAP_DB_TX_ATTENUATION  0x00000200
   360 #define RADIOTAP_DBM_TX_POWER       0x00000200
   361 #define RADIOTAP_ANTENNA            0x00000400
   362 #define RADIOTAP_DB_ANTSIGNAL       0x00000800
   363 #define RADIOTAP_DB_ANTNOISE        0x00001000
   364 #define RADIOTAP_EXT                0x10000000
   365 
   366 #define	RADIOTAP_FLAG_NONE	   0x00	
   367 #define	RADIOTAP_FLAG_CFP	   0x01	
   368 #define	RADIOTAP_FLAG_SHORTPRE	   0x02	
   369 #define	RADIOTAP_FLAG_WEP	   0x04	
   370 #define	RADIOTAP_FLAG_FRAG	   0x08	
   371 #define	RADIOTAP_FLAG_FCS	   0x10	
   372 #define	RADIOTAP_FLAG_DATAPAD	   0x20	
   373 #define	RADIOTAP_FLAG_BADFCS	   0x40	
   374 
   375 #define	RADIOTAP_CHANNEL_TURBO	  0x0010
   376 #define	RADIOTAP_CHANNEL_CCK	  0x0020
   377 #define	RADIOTAP_CHANNEL_OFDM	  0x0040
   378 #define	RADIOTAP_CHANNEL_2GHZ	  0x0080
   379 #define	RADIOTAP_CHANNEL_5GHZ	  0x0100
   380 #define	RADIOTAP_CHANNEL_PASSIVE  0x0200
   381 #define	RADIOTAP_CHANNEL_DYN	  0x0400
   382 #define	RADIOTAP_CHANNEL_GFSK	  0x0800
   383 
   384 #define RADIOTAP_RX_PRESENT (RADIOTAP_TSFT | RADIOTAP_FLAGS | RADIOTAP_RATE | RADIOTAP_CHANNEL | RADIOTAP_DBM_ANTSIGNAL | RADIOTAP_DBM_ANTNOISE)
   385 #define RADIOTAP_RX_LENGTH (8+8+1+1+2+2+1+1)
   386 
   387 #define RADIOTAP_TX_PRESENT (RADIOTAP_TSFT | RADIOTAP_FLAGS  | RADIOTAP_RATE | RADIOTAP_CHANNEL)
   388 #define RADIOTAP_TX_LENGTH (8+8+1+1+2+2)
   389       
   390       if (isTx)
   391         {
   392           wifiMonitorHeaderSize = RADIOTAP_TX_LENGTH;
   393         }
   394       else
   395         {
   396           wifiMonitorHeaderSize = RADIOTAP_RX_LENGTH;
   397         }      
   398 
   399       if (m_captureSize == 0)
   400         {
   401           Write32 (packet->GetSize () + wifiMonitorHeaderSize); // captured size == actual packet size
   402         }
   403       else
   404         {
   405           uint32_t thisCaptureSize = std::min (m_captureSize, packet->GetSize () + wifiMonitorHeaderSize);         
   406           Write32 (thisCaptureSize); 
   407         }
   408       Write32 (packet->GetSize () + wifiMonitorHeaderSize); // actual packet size
   409 
   410       Write8(0); // radiotap version
   411       Write8(0); // padding
   412 
   413       if (isTx)
   414         {
   415           Write16(RADIOTAP_TX_LENGTH); 
   416           Write32(RADIOTAP_TX_PRESENT); 
   417         }
   418       else
   419         {
   420           Write16(RADIOTAP_RX_LENGTH); 
   421           Write32(RADIOTAP_RX_PRESENT); 
   422         }
   423 
   424       Write64(tsft); 
   425       
   426       uint8_t flags = RADIOTAP_FLAG_NONE;
   427       if (isShortPreamble)
   428         {
   429           flags |= RADIOTAP_FLAG_SHORTPRE; 
   430         }
   431       Write8(flags);
   432       
   433 
   434       Write8(rate); 
   435 
   436       Write16((uint16_t) 2437); 
   437 
   438       // we might want to make this setting depend on the WifiMode and
   439       // on the ChannelFrequency at some time in the future. But for now
   440       // I think a fixed setting is more than enough for most purposes.
   441       Write16(RADIOTAP_CHANNEL_OFDM | RADIOTAP_CHANNEL_2GHZ); 
   442     
   443       if (!isTx)
   444         {
   445           
   446           Write8 (RoundToInt8 (signalDbm)); 
   447           Write8 (RoundToInt8 (noiseDbm)); 
   448         }
   449 
   450     } // PCAP_80211_RADIOTAP
   451 
   452     
   453   else
   454     {
   455       NS_LOG_ERROR("unknown PCAP mode");      
   456       return;
   457     }    
   458 
   459   // finally, write rest of packet
   460   if (m_captureSize == 0)
   461     {
   462       packet->CopyData (m_writer, packet->GetSize ());
   463     }
   464   else
   465     {
   466       packet->CopyData (m_writer, m_captureSize - wifiMonitorHeaderSize);      
   467     }
   468 
   469 }
   470     
   471   
   472 void 
   473 PcapWriter::SetCaptureSize (uint32_t size)
   474 {
   475   m_captureSize = size;
   476 }
   477 
   478 int8_t 
   479 PcapWriter::RoundToInt8 (double value)
   480 {
   481   if (value < -128)
   482     {
   483       return -128;
   484     }
   485   if (value > 127)
   486     {
   487       return 127;
   488     }
   489   return ((int8_t) round(value));
   490 }
   491 
   492 
   493 
   494 
   495 
   496 
   497 void
   498 PcapWriter::WriteData (uint8_t const*buffer, uint32_t size)
   499 {
   500   NS_LOG_FUNCTION(this << size);
   501   m_writer->write ((char const *)buffer, size);
   502 }
   503 
   504 
   505 void
   506 PcapWriter::Write64 (uint64_t data)
   507 {
   508   uint8_t buffer[8];
   509   buffer[0] = (data >> 0) & 0xff;
   510   buffer[1] = (data >> 8) & 0xff;
   511   buffer[2] = (data >> 16) & 0xff;
   512   buffer[3] = (data >> 24) & 0xff;
   513   buffer[4] = (data >> 32) & 0xff;
   514   buffer[5] = (data >> 40) & 0xff;
   515   buffer[6] = (data >> 48) & 0xff;
   516   buffer[7] = (data >> 56) & 0xff;
   517   WriteData (buffer, 8);
   518 }
   519 
   520 void
   521 PcapWriter::Write32 (uint32_t data)
   522 {
   523   uint8_t buffer[4];
   524   buffer[0] = (data >> 0) & 0xff;
   525   buffer[1] = (data >> 8) & 0xff;
   526   buffer[2] = (data >> 16) & 0xff;
   527   buffer[3] = (data >> 24) & 0xff;
   528   WriteData (buffer, 4);
   529 }
   530 
   531 void
   532 PcapWriter::Write16 (uint16_t data)
   533 {
   534   uint8_t buffer[2];
   535   buffer[0] = (data >> 0) & 0xff;
   536   buffer[1] = (data >> 8) & 0xff;
   537   WriteData (buffer, 2);
   538 }
   539 
   540 void
   541 PcapWriter::Write8 (uint8_t data)
   542 {
   543   WriteData (&data, 1);
   544 }
   545 
   546 
   547 
   548 } // namespace ns3