|
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
|