RadiotapPacket.cc
Go to the documentation of this file.
1 //
2 // Copyright (c) 2020 Fraunhofer Institute for Applied Information Technology (FIT)
3 // Network Research Group (NET)
4 // Schloss Birlinghoven, 53754 Sankt Augustin, GERMANY
5 // Contact: support@wiback.org
6 //
7 // This file is part of the SENF code tree.
8 // It is licensed under the 3-clause BSD License (aka New BSD License).
9 // See LICENSE.txt in the top level directory for details or visit
10 // https://opensource.org/licenses/BSD-3-Clause
11 //
12 
13 
14 #include "RadiotapPacket.hh"
15 //#include "RadiotapPacket.ih"
16 
17 // Custom includes
18 #include <memory.h>
19 #include <endian.h>
20 #include <boost/io/ios_state.hpp>
21 #include "WLANPacket.hh"
22 #include "MCSInfo.hh"
23 
24 // Compatibility with glibc < 2.9
25 #if !defined(htole32) && !defined(le32toh)
26 # include <byteswap.h>
27 # include <arpa/inet.h>
28 # define htole32(x) (bswap_32(htonl(x)))
29 # define le32toh(x) (ntohl(bswap_32(x)))
30 #endif
31 
32 extern "C" {
33 # include "radiotap/radiotap_iter.h"
34 }
35 
36 #define MHZ_TO_KHZ(freq) ((freq) * 1000)
37 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
38 
39 
40 #define prefix_
41 //-/////////////////////////////////////////////////////////////////////////////////////////////////
42 
44 
45 //-/////////////////////////////////////////////////////////////////////////////////////////////////
46 // Offset table management
47 
48 senf::RadiotapPacketParser::OffsetMap senf::RadiotapPacketParser::offsetMap_;
49 
50 prefix_ void senf::RadiotapPacketParser::parseOffsetTable(boost::uint8_t * data, int maxLength,
51  OffsetTable & table)
52 {
55  &iter, reinterpret_cast<ieee80211_radiotap_header *>(data), maxLength, 0);
56  unsigned size (8u);
57  unsigned extIndex = 0;
58  int last_index = 255;
59  while (ieee80211_radiotap_iterator_next(&iter) == 0) {
60  if (not iter.is_radiotap_ns)
61  continue;
63  continue;
64  if (iter.this_arg_index < last_index)
65  extIndex++;
66  last_index = iter.this_arg_index;
67  table[extIndex * iter.this_arg_index] = iter.this_arg - data;
68  // We need to set size here in the loop since the iter fields are only valid
69  // when at least one present bit is set ...
70  size = iter.this_arg - data + iter.this_arg_size;
71  }
72  table[MAX_INDEX+1] = size;
73 }
74 
75 prefix_ void senf::RadiotapPacketParser::buildOffsetTable(boost::uint32_t presentFlags, OffsetTable & table)
76 {
77  SENF_ASSERT(!(presentFlags & ( (1<<IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE) |
79  (1<<IEEE80211_RADIOTAP_EXT) )),
80  "Extended or vendor fields not supported");
81 
83  memset(&header, 0, sizeof(header));
84  // header.it_version = 0;
85 
86  // Iterating this packet will generate invalid addresses but we don't care since neither
87  // radiotap.c nor we will ever dereference those pointers, we just calculate the offsets.
88  // This works, as long as we don't support extension headers ...
89  header.it_len = 0xFFFF;
90  // Note that all data in the header is little endian!
91  header.it_present = htole32(presentFlags);
92 
93  parseOffsetTable((boost::uint8_t*)&header, header.it_len, table);
94 }
95 
96 //-/////////////////////////////////////////////////////////////////////////////////////////////////
97 // senf::RadiotapPacketParser
98 
100  8, 1, 1, 4, 2, 1, 1, 2, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1, 0, 3, 8, 12 };
101 
103 {
104  if (!has_fcs()) {
105  protect(), data().insert(data().end(), 4u, 0u);
106  init_flags().fcsAtEnd_() = true;
107  }
108  return fcs();
109 }
110 
112 {
113  if (has_fcs()) {
114  validate(RadiotapPacket_HeaderParser::fixed_bytes+4);
115  data().erase(data().end()-4, data().end());
116  flags().fcsAtEnd_() = false;
117  }
118 }
119 
120 prefix_ senf::RadiotapPacketParser::OffsetTable const &
121 senf::RadiotapPacketParser::getTable(boost::uint32_t presentFlags)
122  const
123 {
124  OffsetTable & table (offsetMap_[boost::hash_value(presentFlags)]);
125  if (SENF_UNLIKELY(! table[MAX_INDEX+1]))
126  buildOffsetTable(presentFlags, table);
127  return table;
128 }
129 
130 prefix_ void senf::RadiotapPacketParser::insertRemoveBytes(unsigned from, unsigned to, int bytes)
131 {
132  data_iterator b (i() + from);
133  data_iterator e (i() + to);
134  if (bytes >= 0) {
135  // Insert some bytes cleaning the old bytes to 0 first
136  std::fill(b, e, 0u);
137  if (bytes > 0)
138  // need to protect the parser since data().insert() invalidates iterators
139  protect(), data().insert(e, bytes, 0u);
140  }
141  else { // bytes < 0
142  // Remove some bytes ...
143  // remember: bytes is negative ...
144  if (b < e + bytes)
145  std::fill(b, e + bytes, 0u);
146  data().erase(e + bytes, e);
147  }
148 }
149 
150 prefix_ void senf::RadiotapPacketParser::updatePresentFlags(boost::uint32_t flags)
151 {
152  if (flags == presentFlags())
153  return;
154  validate(bytes());
155 
156  OffsetTable const & oldTable (currentTable());
157  OffsetTable const & newTable (getTable(flags));
158  unsigned b (RadiotapPacket_HeaderParser::fixed_bytes);
159  int cumulativeNewBytes (0);
160 
161  for (unsigned index (0); index <= MAX_INDEX; ++index) {
162  // Skip any unchanged fields
163  for (; index <= MAX_INDEX+1
164  && ((oldTable[index] == 0 && newTable[index] == 0)
165  || (oldTable[index]+cumulativeNewBytes == newTable[index])); ++index)
166  if (newTable[index] != 0)
167  b = newTable[index] + FIELD_SIZE[index];
168  if (index > MAX_INDEX+1)
169  break;
170  // Now skip over all changed fields
171  for (; ! (oldTable[index]!=0 && newTable[index]!=0); ++index) ;
172  // (The condition is not needed here since the last table entry MAX_INDEX+1 is
173  // always != 0 in both tables, BUT newer g++ complains about array access above the bounds :-/
174  if (index > MAX_INDEX+1)
175  break;
176  // index now either points to
177  // a) an entry set in both tables
178  // b) at the end of the table which contains the total length
179  // (remember: the table has a size of MAX_INDEX+2 entries !!)
180  // in both cases, the difference between the new and old size
181  // is found from the difference between the old and the new table
182  // entry
183  int newBytes (newTable[index] - oldTable[index] - cumulativeNewBytes);
184  insertRemoveBytes(b, oldTable[index] + cumulativeNewBytes, newBytes);
185  cumulativeNewBytes += newBytes;
186  b = newTable[index] + FIELD_SIZE[index];
187  }
188  length() += cumulativeNewBytes;
189  presentFlags() = flags;
190  currentTable_ = &newTable;
191 }
192 
194 {
195  if (SENF_LIKELY(mcsPresent()))
196  return WLAN_MCSInfo::getRate(
197  mcs().mcsIndex(),
198  mcs().bandwidth() == 1 ? 40 : 20,
199  mcs().guardInterval());
200  if (ratePresent())
201  return rate() * 1000 / 2;
202  return 0;
203 }
204 
206 {
207  unsigned vhtBandwidths[] = {
208  MHZ_TO_KHZ(20), MHZ_TO_KHZ(40), MHZ_TO_KHZ(40), MHZ_TO_KHZ(40),
209  MHZ_TO_KHZ(80), MHZ_TO_KHZ(80), MHZ_TO_KHZ(80), MHZ_TO_KHZ(80),
210  MHZ_TO_KHZ(80), MHZ_TO_KHZ(80), MHZ_TO_KHZ(80), MHZ_TO_KHZ(160),
211  MHZ_TO_KHZ(160), MHZ_TO_KHZ(160), MHZ_TO_KHZ(160), MHZ_TO_KHZ(160),
212  MHZ_TO_KHZ(160), MHZ_TO_KHZ(160), MHZ_TO_KHZ(160), MHZ_TO_KHZ(160),
213  MHZ_TO_KHZ(160), MHZ_TO_KHZ(160), MHZ_TO_KHZ(160), MHZ_TO_KHZ(160),
214  MHZ_TO_KHZ(160), MHZ_TO_KHZ(160) };
215 
216  if (mcsPresent())
217  return mcs().bandwidth() == 1 ? MHZ_TO_KHZ(40) : MHZ_TO_KHZ(20);
218  if (vhtPresent() and vht().bandwidth() < ARRAY_SIZE(vhtBandwidths))
219  return vhtBandwidths[vht().bandwidth()];
220  return 0;
221 }
222 
223 //-/////////////////////////////////////////////////////////////////////////////////////////////////
224 // senf::RadiotapPacketType
225 
227 {
228  boost::io::ios_all_saver ias(os);
229  os << "Radiotap:\n"
230  << senf::fieldName("version") << unsigned(p->version()) << '\n'
231  << senf::fieldName("length") << unsigned(p->length()) << '\n';
232 
233 # define FIELD(name, sign, desc) \
234  if (p->name ## Present()) \
235  os << senf::fieldName(desc) << sign(p->name()) << '\n';
236 
237 # define ENTER(name) \
238  if (p->name ## Present()) { \
239  packet::Parser::name ## _t subparser (p->name());
240 
241 # define SUBFIELD(name, sign, desc) \
242  os << senf::fieldName(desc) << sign(subparser.name()) << '\n';
243 
244 # define LEAVE() \
245  }
246 
247 # define START_FLAGS(desc) \
248  os << senf::fieldName(desc);
249 
250 # define FLAG(name, desc) \
251  if (subparser.name()) os << desc " "
252 
253 # define END_FLAGS() \
254  os << '\n';
255 
256 static const char * MCSbandwidthDesc[] = { "20", "40", "20L", "20U" };
257 static const char * MCSguardIntervalDesc[] = { "long", "short" };
258 static const char * MCShtFormatDesc[] = { "mixed", "greenfield" };
259 static const char * MCSfecTypeDesc[] = { "BCC", "LDPC" };
260 static const char * MCSmcsIndexDesc[] = { };
261 
262 # define MCS_FLAG(name, desc, longDesc) \
263  if (subparser.name ## Known()) { \
264  os << senf::fieldName(" " desc) << unsigned(subparser.name()); \
265  if (longDesc) \
266  os << " (" << MCS ## name ## Desc[subparser.name()] << ")"; \
267  os << "\n"; }
268 
269 
270 static const char * VHTpartialAidDesc[] = { };
271 static const char * VHTgroupIdDesc[] = { };
272 static const char * VHTbandwidthDesc[] = { };
273 static const char * VHTbeamformedDesc[] = { "yes", "no" };
274 static const char * VHTldpcExtraOfdmSymbolDesc[] = { "yes", "no" };
275 static const char * VHTshortGiNsymDisambiguationDesc[] = { "yes", "no" };
276 static const char * VHTguardIntervalDesc[] = { "long", "short" };
277 static const char * VHTtxOpPsNotAllowedDesc[] = { "yes", "no" };
278 static const char * VHTstbcDesc[] = { "yes", "no" };
279 
280 
281 # define VHT_FLAG(name, desc, longDesc) \
282  if (subparser.name ## Known()) { \
283  os << senf::fieldName(" " desc) << unsigned(subparser.name()); \
284  if (longDesc) \
285  os << " (" << VHT ## name ## Desc[subparser.name()] << ")"; \
286  os << "\n"; }
287 
288 
289 
290  FIELD ( tsft, boost::uint64_t, "MAC timestamp" );
291  ENTER ( flags );
292  START_FLAGS ( "flags" );
293  FLAG ( shortGI, "ShortGI" );
294  FLAG ( badFCS, "BadFCS" );
295  FLAG ( fcsAtEnd, "FCSatEnd" );
296  FLAG ( fragmentation, "Frag" );
297  FLAG ( wep, "WEP" );
298  FLAG ( shortPreamble, "ShortPreamble" );
299  FLAG ( cfp, "CFP" );
300  END_FLAGS ( );
301  LEAVE ( );
302  FIELD ( rate, unsigned, "rate" );
303  ENTER ( channelOptions );
304  SUBFIELD ( freq, unsigned, "channel frequency" );
305  START_FLAGS ( "channel flags" );
306  FLAG ( flag2ghz, "2GHz" );
307  FLAG ( ofdm, "OFDM" );
308  FLAG ( cck, "CCK" );
309  FLAG ( turbo, "Turbo" );
310  FLAG ( quarterRateChannel, "Rate/4" );
311  FLAG ( halfRateChannel, "Rate/2" );
312  FLAG ( gsm, "GSM" );
313  FLAG ( staticTurbo, "StaticTurbo" );
314  FLAG ( gfsk, "GFSK" );
315  FLAG ( cckOfdm, "CCK+OFDM" );
316  FLAG ( passive, "Passive" );
317  FLAG ( flag5ghz, "5GHz" );
318  END_FLAGS ( );
319  LEAVE ( );
320  FIELD ( fhss, unsigned, "FHSS" );
321  FIELD ( dbmAntennaSignal, signed, "antenna signal (dBm)" );
322  FIELD ( dbmAntennaNoise, signed, "antenna noise (dBm)" );
323  FIELD ( lockQuality, unsigned, "lock quality" );
324  FIELD ( txAttenuation, unsigned, "tx attenuation" );
325  FIELD ( dbTxAttenuation, unsigned, "tx attenuation (dB)" );
326  FIELD ( dbmTxAttenuation, signed, "tx attenuation (dBm)" );
327  FIELD ( antenna, unsigned, "antenna" );
328  FIELD ( dbAntennaSignal, unsigned, "antenna signal (dB)" );
329  FIELD ( dbAntennaNoise, unsigned, "antenna noise (dB)" );
330  ENTER ( rxFlags );
331  START_FLAGS ( "rx flags" );
332  FLAG ( badPlcp, "BadPLCP" );
333  END_FLAGS ( );
334  LEAVE ( );
335  ENTER ( txFlags );
336  START_FLAGS ( "tx flags" );
337  FLAG ( fail, "Fail" );
338  FLAG ( txRts, "RTS" );
339  FLAG ( txCts, "CTS" );
340  END_FLAGS ( );
341  LEAVE ( );
342  FIELD ( rtsRetries, unsigned, "rts retries" );
343  FIELD ( dataRetries, unsigned, "data retries" );
344  ENTER ( mcs );
345  START_FLAGS ( "known MCS information" );
346  FLAG ( bandwidthKnown, "bandwidth" );
347  FLAG ( mcsIndexKnown, "MCS index" );
348  FLAG ( guardIntervalKnown, "guard interval" );
349  FLAG ( htFormatKnown, "HT format" );
350  FLAG ( fecTypeKnown, "FEC type" );
351  END_FLAGS ( );
352  os << " MCS information\n" ;
353  MCS_FLAG ( bandwidth, "bandwidth", 1);
354  MCS_FLAG ( guardInterval, "guard interval", 1);
355  MCS_FLAG ( htFormat, "HT format", 1);
356  MCS_FLAG ( fecType, "FEC type", 1);
357  MCS_FLAG ( mcsIndex, "MCS index", 0);
358  LEAVE ( );
359  ENTER ( vht );
360  START_FLAGS ( "known VHT information" );
361  FLAG ( partialAidKnown, "Partial AID" );
362  FLAG ( groupIdKnown, "Group ID" );
363  FLAG ( bandwidthKnown, "Bandwidth" );
364  FLAG ( beamformedKnown, "Beamformed" );
365  FLAG ( ldpcExtraOfdmSymbolKnown, "LDPC Extra OFDM Symbol");
366  FLAG ( shortGiNsymDisambiguationKnown, "Short GI NSYM Disambiguation");
367  FLAG ( guardIntervalKnown, "Guard Interval" );
368  FLAG ( txOpPsNotAllowedKnown, "TxOp PS Not Allowed");
369  FLAG ( stbcKnown, "STBC" );
370  END_FLAGS ( );
371  os << " VHT information\n" ;
372  VHT_FLAG ( partialAid, "Partial AID" , 0);
373  VHT_FLAG ( groupId, "GroupId" , 0);
374  VHT_FLAG ( bandwidth, "Bandwidth Index", 0);
375  VHT_FLAG ( beamformed, "Beamformed", 1);
376  VHT_FLAG ( ldpcExtraOfdmSymbol, "LDPC Extra OFDM Symbol", 1);
377  VHT_FLAG ( shortGiNsymDisambiguation, "Short GI NSYM Disambiguation", 1);
378  VHT_FLAG ( guardInterval, "Guard Interval", 1);
379  VHT_FLAG ( txOpPsNotAllowed, "TxOp PS Not Allowed", 1);
380  VHT_FLAG ( stbc, "STBC", 1);
381  LEAVE ( );
382 
383  if (p->flagsPresent() && p->flags().fcsAtEnd())
384  os << senf::fieldName("fcs") << unsigned(p->fcs()) << '\n';
385 
386 # undef END_FLAGS
387 # undef FLAG
388 # undef START_FLAGS
389 # undef LEAVE
390 # undef SUBFIELD
391 # undef ENTER
392 # undef FIELD
393 # undef MCS_FLAG
394 # undef VHT_FLAG
395 }
396 
398 {
399  // ?? Why the heck do we need the +0? Otherwise we get an
400  // 'undefined reference to 'RadiotapPacket_HeaderParser::fixed_bytes'
401  p->length() << RadiotapPacket_HeaderParser::fixed_bytes+0;
402 }
403 
405 {
406  static factory_t frameTypeFactory[] = { WLANPacket_MgtFrame::factory(),
409  no_factory() };
410  return frameTypeFactory[p->frameType()];
411 }
412 
415 {
416  parser rtParser (p.parser());
417  size_type h (senf::bytes(rtParser));
418  size_type t (rtParser.flagsPresent() && rtParser.flags().fcsAtEnd() ? 4 : 0);
419  return p.size() < h+t
420  ? no_range()
421  : optional_range( range(p.data().begin() + h, p.data().end() - t) );
422 }
423 
424 //-/////////////////////////////////////////////////////////////////////////////////////////////////
425 #undef prefix_
426 
427 
428 // Local Variables:
429 // mode: c++
430 // fill-column: 100
431 // c-file-style: "senf"
432 // indent-tabs-mode: nil
433 // ispell-local-dictionary: "american"
434 // compile-command: "scons -u test"
435 // comment-column: 40
436 // End:
#define START_FLAGS(desc)
static optional_range nextPacketRange(packet const &p)
#define LEAVE()
static unsigned getRate(std::uint8_t mcsIndex, unsigned bandwidth, bool shortGI)
Definition: MCSInfo.cc:89
PacketInterpreterBase::optional_range optional_range
Definition: PacketType.hh:111
#define ENTER(name)
Radiotap header.
static void dump(packet p, std::ostream &os)
int ieee80211_radiotap_iterator_next(struct ieee80211_radiotap_iterator *iterator)
Definition: radiotap.c:246
UInt16LSBParser length() const
std::string fieldName(std::string const &s)
Definition: DumpFormat.cc:28
#define SUBFIELD(name, sign, desc)
#define SENF_LIKELY(x)
iterator begin() const
Return iterator to beginning.
PacketParserBase::size_type bytes(Parser const &p)
Return raw size parsed by the given parser object.
#define prefix_
#define ARRAY_SIZE(arr)
FIELD(tsft, UInt64LSBParser, TSFT_INDEX)
PacketData & data() const
Access the packets raw data container.
iterator end() const
Return iterator to end.
Protocol specific packet handle.
Definition: Packet.hh:87
int ieee80211_radiotap_iterator_init(struct ieee80211_radiotap_iterator *iterator, struct ieee80211_radiotap_header *radiotap_header, int max_length, const struct ieee80211_radiotap_vendor_namespaces *vns)
Definition: radiotap.c:105
size_type bytes() const
#define FLAG(name, desc)
#define END_FLAGS()
data_iterator i() const
Return beginning of data to parse.
senf::detail::packet::size_type size_type
Definition: PacketType.hh:106
flags_t flags(unsigned extIndex=0)
PacketInterpreterBase::range range
Definition: PacketType.hh:110
#define SENF_ASSERT(x, comment)
static void init(packet p)
size_type size() const
Return size of packet in bytes.
PacketData & data() const
Access the packets raw data container.
struct ieee80211_mcs_info mcs
void erase(iterator pos)
Parse 32bit unsigned byte aligned integer.
Definition: IntParser.hh:310
void insert(iterator pos, byte v)
PacketInterpreterBase::factory_t factory_t
Definition: PacketType.hh:112
static factory_t factory()
Return factory for packets of specific type.
void validate(size_type size) const
Validate size of data container.
static factory_t nextPacketType(packet p)
802.11 WLANPacket public header
SENF_PACKET_INSTANTIATE_TEMPLATE(senf::RadiotapPacket)
ParserProtector protect() const
#define htole32(x)
UInt32LSBParser presentFlags() const
static unsigned const FIELD_SIZE[MAX_INDEX+2]
#define SENF_UNLIKELY(x)
detail::packet::iterator data_iterator
Raw data iterator type.
__be16 freq
#define MHZ_TO_KHZ(freq)
Parser parser() const
Access packet field parser directly.