radiotap.c
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 /*
15  * Radiotap parser
16  *
17  * Copyright 2007 Andy Green <andy@warmcat.com>
18  * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
19  *
20  * This program is free software; you can redistribute it and/or modify
21  * it under the terms of the GNU General Public License version 2 as
22  * published by the Free Software Foundation.
23  *
24  * Alternatively, this software may be distributed under the terms of BSD
25  * license.
26  *
27  * See COPYING for more details.
28  */
29 #include "radiotap_iter.h"
30 #include "platform.h"
31 
32 /* function prototypes and related defs are in radiotap_iter.h */
33 
34 static const struct radiotap_align_size rtap_namespace_sizes[] = {
35  [IEEE80211_RADIOTAP_TSFT] = { .align = 8, .size = 8, },
36  [IEEE80211_RADIOTAP_FLAGS] = { .align = 1, .size = 1, },
37  [IEEE80211_RADIOTAP_RATE] = { .align = 1, .size = 1, },
38  [IEEE80211_RADIOTAP_CHANNEL] = { .align = 2, .size = 4, },
39  [IEEE80211_RADIOTAP_FHSS] = { .align = 2, .size = 2, },
40  [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = { .align = 1, .size = 1, },
41  [IEEE80211_RADIOTAP_DBM_ANTNOISE] = { .align = 1, .size = 1, },
42  [IEEE80211_RADIOTAP_LOCK_QUALITY] = { .align = 2, .size = 2, },
43  [IEEE80211_RADIOTAP_TX_ATTENUATION] = { .align = 2, .size = 2, },
44  [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = { .align = 2, .size = 2, },
45  [IEEE80211_RADIOTAP_DBM_TX_POWER] = { .align = 1, .size = 1, },
46  [IEEE80211_RADIOTAP_ANTENNA] = { .align = 1, .size = 1, },
47  [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = { .align = 1, .size = 1, },
48  [IEEE80211_RADIOTAP_DB_ANTNOISE] = { .align = 1, .size = 1, },
49  [IEEE80211_RADIOTAP_RX_FLAGS] = { .align = 2, .size = 2, },
50  [IEEE80211_RADIOTAP_TX_FLAGS] = { .align = 2, .size = 2, },
51  [IEEE80211_RADIOTAP_RTS_RETRIES] = { .align = 1, .size = 1, },
52  [IEEE80211_RADIOTAP_DATA_RETRIES] = { .align = 1, .size = 1, },
53  [IEEE80211_RADIOTAP_MCS] = { .align = 1, .size = 3, },
54  [IEEE80211_RADIOTAP_AMPDU_STATUS] = { .align = 4, .size = 8, },
55  [IEEE80211_RADIOTAP_VHT] = { .align = 2, .size = 12, },
56  [IEEE80211_RADIOTAP_TIMESTAMP] = { .align = 8, .size = 12, },
57  /*
58  * add more here as they are defined in radiotap.h
59  */
60 };
61 
62 static const struct ieee80211_radiotap_namespace radiotap_ns = {
63  .n_bits = sizeof(rtap_namespace_sizes) / sizeof(rtap_namespace_sizes[0]),
64  .align_size = rtap_namespace_sizes,
65 };
66 
107  struct ieee80211_radiotap_header *radiotap_header,
108  int max_length, const struct ieee80211_radiotap_vendor_namespaces *vns)
109 {
110  /* must at least have the radiotap header */
111  if (max_length < (int)sizeof(struct ieee80211_radiotap_header))
112  return -EINVAL;
113 
114  /* Linux only supports version 0 radiotap format */
115  if (radiotap_header->it_version)
116  return -EINVAL;
117 
118  /* sanity check for allowed length and radiotap length field */
119  if (max_length < get_unaligned_le16(&radiotap_header->it_len))
120  return -EINVAL;
121 
122  iterator->_rtheader = radiotap_header;
123  iterator->_max_length = get_unaligned_le16(&radiotap_header->it_len);
124  iterator->_arg_index = 0;
125  iterator->_bitmap_shifter = get_unaligned_le32(&radiotap_header->it_present);
126  iterator->_arg = (uint8_t *)radiotap_header + sizeof(*radiotap_header);
127  iterator->_reset_on_ext = 0;
128  iterator->_next_bitmap = &radiotap_header->it_present;
129  iterator->_next_bitmap++;
130  iterator->_vns = vns;
131  iterator->current_namespace = &radiotap_ns;
132  iterator->is_radiotap_ns = 1;
133 #ifdef RADIOTAP_SUPPORT_OVERRIDES
134  iterator->n_overrides = 0;
135  iterator->overrides = NULL;
136 #endif
137 
138  /* find payload start allowing for extended bitmap(s) */
139 
140  if (iterator->_bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT)) {
141  if ((unsigned long)iterator->_arg -
142  (unsigned long)iterator->_rtheader + sizeof(uint32_t) >
143  (unsigned long)iterator->_max_length)
144  return -EINVAL;
145  while (get_unaligned_le32(iterator->_arg) &
146  (1 << IEEE80211_RADIOTAP_EXT)) {
147  iterator->_arg += sizeof(uint32_t);
148 
149  /*
150  * check for insanity where the present bitmaps
151  * keep claiming to extend up to or even beyond the
152  * stated radiotap header length
153  */
154 
155  if ((unsigned long)iterator->_arg -
156  (unsigned long)iterator->_rtheader +
157  sizeof(uint32_t) >
158  (unsigned long)iterator->_max_length)
159  return -EINVAL;
160  }
161 
162  iterator->_arg += sizeof(uint32_t);
163 
164  /*
165  * no need to check again for blowing past stated radiotap
166  * header length, because ieee80211_radiotap_iterator_next
167  * checks it before it is dereferenced
168  */
169  }
170 
171  iterator->this_arg = iterator->_arg;
172 
173  /* we are all initialized happily */
174 
175  return 0;
176 }
177 
178 static void find_ns(struct ieee80211_radiotap_iterator *iterator,
179  uint32_t oui, uint8_t subns)
180 {
181  int i;
182 
183  iterator->current_namespace = NULL;
184 
185  if (!iterator->_vns)
186  return;
187 
188  for (i = 0; i < iterator->_vns->n_ns; i++) {
189  if (iterator->_vns->ns[i].oui != oui)
190  continue;
191  if (iterator->_vns->ns[i].subns != subns)
192  continue;
193 
194  iterator->current_namespace = &iterator->_vns->ns[i];
195  break;
196  }
197 }
198 
199 #ifdef RADIOTAP_SUPPORT_OVERRIDES
200 static int find_override(struct ieee80211_radiotap_iterator *iterator,
201  int *align, int *size)
202 {
203  int i;
204 
205  if (!iterator->overrides)
206  return 0;
207 
208  for (i = 0; i < iterator->n_overrides; i++) {
209  if (iterator->_arg_index == iterator->overrides[i].field) {
210  *align = iterator->overrides[i].align;
211  *size = iterator->overrides[i].size;
212  if (!*align) /* erroneous override */
213  return 0;
214  return 1;
215  }
216  }
217 
218  return 0;
219 }
220 #endif
221 
222 
247  struct ieee80211_radiotap_iterator *iterator)
248 {
249  while (1) {
250  int hit = 0;
251  int pad, align, size, subns;
252  uint32_t oui;
253 
254  /* if no more EXT bits, that's it */
255  if ((iterator->_arg_index % 32) == IEEE80211_RADIOTAP_EXT &&
256  !(iterator->_bitmap_shifter & 1))
257  return -ENOENT;
258 
259  if (!(iterator->_bitmap_shifter & 1))
260  goto next_entry; /* arg not present */
261 
262  /* get alignment/size of data */
263  switch (iterator->_arg_index % 32) {
266  align = 1;
267  size = 0;
268  break;
270  align = 2;
271  size = 6;
272  break;
273  default:
274 #ifdef RADIOTAP_SUPPORT_OVERRIDES
275  if (find_override(iterator, &align, &size)) {
276  /* all set */
277  } else
278 #endif
279  if (!iterator->current_namespace ||
280  iterator->_arg_index >= iterator->current_namespace->n_bits) {
281  if (iterator->current_namespace == &radiotap_ns)
282  return -ENOENT;
283  align = 0;
284  } else {
285  align = iterator->current_namespace->align_size[iterator->_arg_index].align;
286  size = iterator->current_namespace->align_size[iterator->_arg_index].size;
287  }
288  if (!align) {
289  /* skip all subsequent data */
290  iterator->_arg = iterator->_next_ns_data;
291  /* give up on this namespace */
292  iterator->current_namespace = NULL;
293  goto next_entry;
294  }
295  break;
296  }
297 
298  /*
299  * arg is present, account for alignment padding
300  *
301  * Note that these alignments are relative to the start
302  * of the radiotap header. There is no guarantee
303  * that the radiotap header itself is aligned on any
304  * kind of boundary.
305  *
306  * The above is why get_unaligned() is used to dereference
307  * multibyte elements from the radiotap area.
308  */
309 
310  pad = ((unsigned long)iterator->_arg -
311  (unsigned long)iterator->_rtheader) & (align - 1);
312 
313  if (pad)
314  iterator->_arg += align - pad;
315 
316  if (iterator->_arg_index % 32 == IEEE80211_RADIOTAP_VENDOR_NAMESPACE) {
317  int vnslen;
318 
319  if ((unsigned long)iterator->_arg + size -
320  (unsigned long)iterator->_rtheader >
321  (unsigned long)iterator->_max_length)
322  return -EINVAL;
323 
324  oui = (*iterator->_arg << 16) |
325  (*(iterator->_arg + 1) << 8) |
326  *(iterator->_arg + 2);
327  subns = *(iterator->_arg + 3);
328 
329  find_ns(iterator, oui, subns);
330 
331  vnslen = get_unaligned_le16(iterator->_arg + 4);
332  iterator->_next_ns_data = iterator->_arg + size + vnslen;
333  if (!iterator->current_namespace)
334  size += vnslen;
335  }
336 
337  /*
338  * this is what we will return to user, but we need to
339  * move on first so next call has something fresh to test
340  */
341  iterator->this_arg_index = iterator->_arg_index;
342  iterator->this_arg = iterator->_arg;
343  iterator->this_arg_size = size;
344 
345  /* internally move on the size of this arg */
346  iterator->_arg += size;
347 
348  /*
349  * check for insanity where we are given a bitmap that
350  * claims to have more arg content than the length of the
351  * radiotap section. We will normally end up equalling this
352  * max_length on the last arg, never exceeding it.
353  */
354 
355  if ((unsigned long)iterator->_arg -
356  (unsigned long)iterator->_rtheader >
357  (unsigned long)iterator->_max_length)
358  return -EINVAL;
359 
360  /* these special ones are valid in each bitmap word */
361  switch (iterator->_arg_index % 32) {
363  iterator->_reset_on_ext = 1;
364 
365  iterator->is_radiotap_ns = 0;
366  /*
367  * If parser didn't register this vendor
368  * namespace with us, allow it to show it
369  * as 'raw. Do do that, set argument index
370  * to vendor namespace.
371  */
372  iterator->this_arg_index =
374  if (!iterator->current_namespace)
375  hit = 1;
376  goto next_entry;
378  iterator->_reset_on_ext = 1;
379  iterator->current_namespace = &radiotap_ns;
380  iterator->is_radiotap_ns = 1;
381  goto next_entry;
383  /*
384  * bit 31 was set, there is more
385  * -- move to next u32 bitmap
386  */
387  iterator->_bitmap_shifter =
388  get_unaligned_le32(iterator->_next_bitmap);
389  iterator->_next_bitmap++;
390  if (iterator->_reset_on_ext)
391  iterator->_arg_index = 0;
392  else
393  iterator->_arg_index++;
394  iterator->_reset_on_ext = 0;
395  break;
396  default:
397  /* we've got a hit! */
398  hit = 1;
399  next_entry:
400  iterator->_bitmap_shifter >>= 1;
401  iterator->_arg_index++;
402  }
403 
404  /* if we found a valid arg earlier, return it now */
405  if (hit)
406  return 0;
407  }
408 }
#define get_unaligned_le16(p)
Definition: platform.h:31
int ieee80211_radiotap_iterator_next(struct ieee80211_radiotap_iterator *iterator)
Definition: radiotap.c:246
const struct radiotap_override * overrides
Definition: radiotap_iter.h:86
#define get_unaligned_le32(p)
Definition: platform.h:32
unsigned char * _next_ns_data
Definition: radiotap_iter.h:82
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
const struct ieee80211_radiotap_namespace * ns
Definition: radiotap_iter.h:41
const struct ieee80211_radiotap_namespace * current_namespace
Definition: radiotap_iter.h:80
raw_container::iterator iterator
Definition: PacketTypes.hh:69
const struct ieee80211_radiotap_vendor_namespaces * _vns
Definition: radiotap_iter.h:79
const struct radiotap_align_size * align_size
Definition: radiotap_iter.h:34
struct ieee80211_radiotap_header * _rtheader
Definition: radiotap_iter.h:78