1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
3 * Copyright (c) 2005,2006 INRIA
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;
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.
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
18 * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
22 * Documentation kindly pointed out by Tom Henderson:
23 * http://wiki.ethereal.com/Development/LibpcapFileFormat
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"
36 NS_LOG_COMPONENT_DEFINE ("PcapWriter");
40 NS_OBJECT_ENSURE_REGISTERED (PcapWriter);
47 PCAP_80211_PRISM = 119,
48 PCAP_80211_RADIOTAP = 127,
52 PcapWriter::GetTypeId (void)
54 static TypeId tid = TypeId ("ns3::PcapWriter")
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.",
60 MakeUintegerAccessor (&PcapWriter::m_captureSize),
61 MakeUintegerChecker<uint32_t> ())
66 PcapWriter::PcapWriter ()
68 NS_LOG_FUNCTION (this);
69 NS_LOG_LOGIC ("m_writer = 0");
73 PcapWriter::~PcapWriter ()
75 NS_LOG_FUNCTION (this);
79 NS_LOG_LOGIC ("m_writer nonzero " << m_writer);
80 if (m_writer->is_open ())
82 NS_LOG_LOGIC ("m_writer open. Closing " << m_writer);
86 NS_LOG_LOGIC ("Deleting writer " << m_writer);
89 NS_LOG_LOGIC ("m_writer = 0");
94 NS_LOG_LOGIC ("m_writer == 0");
99 PcapWriter::Open (std::string const &name)
101 NS_LOG_FUNCTION (this << name);
102 NS_ABORT_MSG_UNLESS (m_writer == 0, "PcapWriter::Open(): m_writer already allocated (std::ofstream leak detected)");
104 m_writer = new std::ofstream ();
105 NS_ABORT_MSG_UNLESS (m_writer, "PcapWriter::Open(): Cannot allocate m_writer");
107 NS_LOG_LOGIC ("Created writer " << m_writer);
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");
112 NS_ASSERT_MSG (m_writer->is_open (), "PcapWriter::Open(): m_writer not open");
114 NS_LOG_LOGIC ("Writer opened successfully");
118 PcapWriter::WriteEthernetHeader (void)
120 NS_LOG_FUNCTION_NOARGS ();
121 WriteHeader (PCAP_ETHERNET);
125 PcapWriter::WriteIpHeader (void)
127 NS_LOG_FUNCTION_NOARGS ();
128 WriteHeader (PCAP_RAW_IP);
132 PcapWriter::WriteWifiHeader (void)
134 NS_LOG_FUNCTION_NOARGS ();
135 WriteHeader (PCAP_80211);
139 PcapWriter::WriteWifiRadiotapHeader (void)
141 NS_LOG_FUNCTION_NOARGS ();
142 WriteHeader (PCAP_80211_RADIOTAP);
146 PcapWriter::WriteWifiPrismHeader (void)
148 NS_LOG_FUNCTION_NOARGS ();
149 WriteHeader (PCAP_80211_PRISM);
153 PcapWriter::WritePppHeader (void)
155 NS_LOG_FUNCTION_NOARGS ();
156 WriteHeader (PCAP_PPP);
160 PcapWriter::WriteHeader (uint32_t network)
162 NS_LOG_FUNCTION (this << network);
163 Write32 (0xa1b2c3d4);
170 m_pcapMode = network;
174 PcapWriter::WritePacket (Ptr<const Packet> packet)
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)
186 thisCaptureSize = packet->GetSize ();
190 thisCaptureSize = std::min (m_captureSize, packet->GetSize ());
192 Write32 (thisCaptureSize);
193 Write32 (packet->GetSize ()); // actual packet size
194 packet->CopyData (m_writer, thisCaptureSize);
199 void PcapWriter::WriteWifiMonitorPacket(Ptr<const Packet> packet, uint16_t channelFreqMhz,
200 uint32_t rate, bool isShortPreamble, bool isTx,
201 double signalDbm, double noiseDbm)
203 NS_LOG_FUNCTION (this << packet->GetSize() << channelFreqMhz << rate << isShortPreamble << isTx << signalDbm << noiseDbm);
210 if (m_pcapMode == PCAP_80211)
212 WritePacket (packet);
216 /* the following is common between PRISM and RADIOTAP */
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);
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;
236 uint32_t wifiMonitorHeaderSize;
238 if (m_pcapMode == PCAP_80211_PRISM)
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
254 #define PRISM_STATUS_PRESENT 0
255 #define PRISM_STATUS_ABSENT 1
256 #define PRISM_ITEM_LENGTH 4
259 wifiMonitorHeaderSize = PRISM_MSG_LENGTH;
260 if (m_captureSize == 0)
262 Write32 (packet->GetSize () + wifiMonitorHeaderSize); // captured size == actual packet size
266 uint32_t thisCaptureSize = std::min (m_captureSize, packet->GetSize () + wifiMonitorHeaderSize);
267 Write32 (thisCaptureSize);
269 Write32 (packet->GetSize () + wifiMonitorHeaderSize); // actual packet size
271 Write32(PRISM_MSG_CODE);
272 Write32(PRISM_MSG_LENGTH);
273 WriteData((const uint8_t *)"unknown wifi device!!!!!!!!", 16);
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 ) );
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
287 Write32((uint32_t) tsft);
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);
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));
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
317 Write32(PRISM_DID_SIGNAL);
318 Write16(PRISM_STATUS_PRESENT);
319 Write16(PRISM_ITEM_LENGTH);
320 Write32((uint32_t)round(signalDbm));
322 Write32(PRISM_DID_NOISE);
323 Write16(PRISM_STATUS_PRESENT);
324 Write16(PRISM_ITEM_LENGTH);
325 Write32((uint32_t)round(noiseDbm));
327 Write32(PRISM_DID_RATE);
328 Write16(PRISM_STATUS_PRESENT);
329 Write16(PRISM_ITEM_LENGTH);
332 Write32(PRISM_DID_ISTX);
333 Write16(PRISM_STATUS_PRESENT);
334 Write16(PRISM_ITEM_LENGTH);
335 Write32(isTx ? 1 : 0);
337 Write32(PRISM_DID_FRMLEN);
338 Write16(PRISM_STATUS_ABSENT);
339 Write16(PRISM_ITEM_LENGTH);
340 Write32(packet->GetSize ());
344 } // PCAP_80211_PRISM
346 else if (m_pcapMode == PCAP_80211_RADIOTAP)
348 NS_LOG_LOGIC("writing radiotap packet");
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
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
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
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)
387 #define RADIOTAP_TX_PRESENT (RADIOTAP_TSFT | RADIOTAP_FLAGS | RADIOTAP_RATE | RADIOTAP_CHANNEL)
388 #define RADIOTAP_TX_LENGTH (8+8+1+1+2+2)
392 wifiMonitorHeaderSize = RADIOTAP_TX_LENGTH;
396 wifiMonitorHeaderSize = RADIOTAP_RX_LENGTH;
399 if (m_captureSize == 0)
401 Write32 (packet->GetSize () + wifiMonitorHeaderSize); // captured size == actual packet size
405 uint32_t thisCaptureSize = std::min (m_captureSize, packet->GetSize () + wifiMonitorHeaderSize);
406 Write32 (thisCaptureSize);
408 Write32 (packet->GetSize () + wifiMonitorHeaderSize); // actual packet size
410 Write8(0); // radiotap version
411 Write8(0); // padding
415 Write16(RADIOTAP_TX_LENGTH);
416 Write32(RADIOTAP_TX_PRESENT);
420 Write16(RADIOTAP_RX_LENGTH);
421 Write32(RADIOTAP_RX_PRESENT);
426 uint8_t flags = RADIOTAP_FLAG_NONE;
429 flags |= RADIOTAP_FLAG_SHORTPRE;
436 Write16((uint16_t) 2437);
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);
446 Write8 (RoundToInt8 (signalDbm));
447 Write8 (RoundToInt8 (noiseDbm));
450 } // PCAP_80211_RADIOTAP
455 NS_LOG_ERROR("unknown PCAP mode");
459 // finally, write rest of packet
460 if (m_captureSize == 0)
462 packet->CopyData (m_writer, packet->GetSize ());
466 packet->CopyData (m_writer, m_captureSize - wifiMonitorHeaderSize);
473 PcapWriter::SetCaptureSize (uint32_t size)
475 m_captureSize = size;
479 PcapWriter::RoundToInt8 (double value)
489 return ((int8_t) round(value));
498 PcapWriter::WriteData (uint8_t const*buffer, uint32_t size)
500 NS_LOG_FUNCTION(this << size);
501 m_writer->write ((char const *)buffer, size);
506 PcapWriter::Write64 (uint64_t data)
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);
521 PcapWriter::Write32 (uint32_t data)
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);
532 PcapWriter::Write16 (uint16_t data)
535 buffer[0] = (data >> 0) & 0xff;
536 buffer[1] = (data >> 8) & 0xff;
537 WriteData (buffer, 2);
541 PcapWriter::Write8 (uint8_t data)
543 WriteData (&data, 1);