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