Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
radiotap.c
Go to the documentation of this file.
1 /*
2  * Radiotap parser
3  *
4  * Copyright 2007 Andy Green <[email protected]>
5  * Copyright 2009 Johannes Berg <[email protected]>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  *
11  * Alternatively, this software may be distributed under the terms of BSD
12  * license.
13  *
14  * See COPYING for more details.
15  */
16 
17 #include <linux/kernel.h>
18 #include <linux/export.h>
19 #include <net/cfg80211.h>
20 #include <net/ieee80211_radiotap.h>
21 #include <asm/unaligned.h>
22 
23 /* function prototypes and related defs are in include/net/cfg80211.h */
24 
25 static const struct radiotap_align_size rtap_namespace_sizes[] = {
26  [IEEE80211_RADIOTAP_TSFT] = { .align = 8, .size = 8, },
27  [IEEE80211_RADIOTAP_FLAGS] = { .align = 1, .size = 1, },
28  [IEEE80211_RADIOTAP_RATE] = { .align = 1, .size = 1, },
29  [IEEE80211_RADIOTAP_CHANNEL] = { .align = 2, .size = 4, },
30  [IEEE80211_RADIOTAP_FHSS] = { .align = 2, .size = 2, },
31  [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = { .align = 1, .size = 1, },
32  [IEEE80211_RADIOTAP_DBM_ANTNOISE] = { .align = 1, .size = 1, },
33  [IEEE80211_RADIOTAP_LOCK_QUALITY] = { .align = 2, .size = 2, },
34  [IEEE80211_RADIOTAP_TX_ATTENUATION] = { .align = 2, .size = 2, },
35  [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = { .align = 2, .size = 2, },
36  [IEEE80211_RADIOTAP_DBM_TX_POWER] = { .align = 1, .size = 1, },
37  [IEEE80211_RADIOTAP_ANTENNA] = { .align = 1, .size = 1, },
38  [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = { .align = 1, .size = 1, },
39  [IEEE80211_RADIOTAP_DB_ANTNOISE] = { .align = 1, .size = 1, },
40  [IEEE80211_RADIOTAP_RX_FLAGS] = { .align = 2, .size = 2, },
41  [IEEE80211_RADIOTAP_TX_FLAGS] = { .align = 2, .size = 2, },
42  [IEEE80211_RADIOTAP_RTS_RETRIES] = { .align = 1, .size = 1, },
43  [IEEE80211_RADIOTAP_DATA_RETRIES] = { .align = 1, .size = 1, },
44  [IEEE80211_RADIOTAP_MCS] = { .align = 1, .size = 3, },
45  [IEEE80211_RADIOTAP_AMPDU_STATUS] = { .align = 4, .size = 8, },
46  /*
47  * add more here as they are defined in radiotap.h
48  */
49 };
50 
51 static const struct ieee80211_radiotap_namespace radiotap_ns = {
52  .n_bits = ARRAY_SIZE(rtap_namespace_sizes),
53  .align_size = rtap_namespace_sizes,
54 };
55 
96  struct ieee80211_radiotap_iterator *iterator,
97  struct ieee80211_radiotap_header *radiotap_header,
98  int max_length, const struct ieee80211_radiotap_vendor_namespaces *vns)
99 {
100  /* Linux only supports version 0 radiotap format */
101  if (radiotap_header->it_version)
102  return -EINVAL;
103 
104  /* sanity check for allowed length and radiotap length field */
105  if (max_length < get_unaligned_le16(&radiotap_header->it_len))
106  return -EINVAL;
107 
108  iterator->_rtheader = radiotap_header;
109  iterator->_max_length = get_unaligned_le16(&radiotap_header->it_len);
110  iterator->_arg_index = 0;
111  iterator->_bitmap_shifter = get_unaligned_le32(&radiotap_header->it_present);
112  iterator->_arg = (uint8_t *)radiotap_header + sizeof(*radiotap_header);
113  iterator->_reset_on_ext = 0;
114  iterator->_next_bitmap = &radiotap_header->it_present;
115  iterator->_next_bitmap++;
116  iterator->_vns = vns;
117  iterator->current_namespace = &radiotap_ns;
118  iterator->is_radiotap_ns = 1;
119 
120  /* find payload start allowing for extended bitmap(s) */
121 
122  if (iterator->_bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT)) {
123  while (get_unaligned_le32(iterator->_arg) &
124  (1 << IEEE80211_RADIOTAP_EXT)) {
125  iterator->_arg += sizeof(uint32_t);
126 
127  /*
128  * check for insanity where the present bitmaps
129  * keep claiming to extend up to or even beyond the
130  * stated radiotap header length
131  */
132 
133  if ((unsigned long)iterator->_arg -
134  (unsigned long)iterator->_rtheader >
135  (unsigned long)iterator->_max_length)
136  return -EINVAL;
137  }
138 
139  iterator->_arg += sizeof(uint32_t);
140 
141  /*
142  * no need to check again for blowing past stated radiotap
143  * header length, because ieee80211_radiotap_iterator_next
144  * checks it before it is dereferenced
145  */
146  }
147 
148  iterator->this_arg = iterator->_arg;
149 
150  /* we are all initialized happily */
151 
152  return 0;
153 }
155 
156 static void find_ns(struct ieee80211_radiotap_iterator *iterator,
158 {
159  int i;
160 
161  iterator->current_namespace = NULL;
162 
163  if (!iterator->_vns)
164  return;
165 
166  for (i = 0; i < iterator->_vns->n_ns; i++) {
167  if (iterator->_vns->ns[i].oui != oui)
168  continue;
169  if (iterator->_vns->ns[i].subns != subns)
170  continue;
171 
172  iterator->current_namespace = &iterator->_vns->ns[i];
173  break;
174  }
175 }
176 
177 
178 
203  struct ieee80211_radiotap_iterator *iterator)
204 {
205  while (1) {
206  int hit = 0;
207  int pad, align, size, subns;
208  uint32_t oui;
209 
210  /* if no more EXT bits, that's it */
211  if ((iterator->_arg_index % 32) == IEEE80211_RADIOTAP_EXT &&
212  !(iterator->_bitmap_shifter & 1))
213  return -ENOENT;
214 
215  if (!(iterator->_bitmap_shifter & 1))
216  goto next_entry; /* arg not present */
217 
218  /* get alignment/size of data */
219  switch (iterator->_arg_index % 32) {
222  align = 1;
223  size = 0;
224  break;
226  align = 2;
227  size = 6;
228  break;
229  default:
230  if (!iterator->current_namespace ||
231  iterator->_arg_index >= iterator->current_namespace->n_bits) {
232  if (iterator->current_namespace == &radiotap_ns)
233  return -ENOENT;
234  align = 0;
235  } else {
236  align = iterator->current_namespace->align_size[iterator->_arg_index].align;
237  size = iterator->current_namespace->align_size[iterator->_arg_index].size;
238  }
239  if (!align) {
240  /* skip all subsequent data */
241  iterator->_arg = iterator->_next_ns_data;
242  /* give up on this namespace */
243  iterator->current_namespace = NULL;
244  goto next_entry;
245  }
246  break;
247  }
248 
249  /*
250  * arg is present, account for alignment padding
251  *
252  * Note that these alignments are relative to the start
253  * of the radiotap header. There is no guarantee
254  * that the radiotap header itself is aligned on any
255  * kind of boundary.
256  *
257  * The above is why get_unaligned() is used to dereference
258  * multibyte elements from the radiotap area.
259  */
260 
261  pad = ((unsigned long)iterator->_arg -
262  (unsigned long)iterator->_rtheader) & (align - 1);
263 
264  if (pad)
265  iterator->_arg += align - pad;
266 
267  if (iterator->_arg_index % 32 == IEEE80211_RADIOTAP_VENDOR_NAMESPACE) {
268  int vnslen;
269 
270  if ((unsigned long)iterator->_arg + size -
271  (unsigned long)iterator->_rtheader >
272  (unsigned long)iterator->_max_length)
273  return -EINVAL;
274 
275  oui = (*iterator->_arg << 16) |
276  (*(iterator->_arg + 1) << 8) |
277  *(iterator->_arg + 2);
278  subns = *(iterator->_arg + 3);
279 
280  find_ns(iterator, oui, subns);
281 
282  vnslen = get_unaligned_le16(iterator->_arg + 4);
283  iterator->_next_ns_data = iterator->_arg + size + vnslen;
284  if (!iterator->current_namespace)
285  size += vnslen;
286  }
287 
288  /*
289  * this is what we will return to user, but we need to
290  * move on first so next call has something fresh to test
291  */
292  iterator->this_arg_index = iterator->_arg_index;
293  iterator->this_arg = iterator->_arg;
294  iterator->this_arg_size = size;
295 
296  /* internally move on the size of this arg */
297  iterator->_arg += size;
298 
299  /*
300  * check for insanity where we are given a bitmap that
301  * claims to have more arg content than the length of the
302  * radiotap section. We will normally end up equalling this
303  * max_length on the last arg, never exceeding it.
304  */
305 
306  if ((unsigned long)iterator->_arg -
307  (unsigned long)iterator->_rtheader >
308  (unsigned long)iterator->_max_length)
309  return -EINVAL;
310 
311  /* these special ones are valid in each bitmap word */
312  switch (iterator->_arg_index % 32) {
314  iterator->_reset_on_ext = 1;
315 
316  iterator->is_radiotap_ns = 0;
317  /*
318  * If parser didn't register this vendor
319  * namespace with us, allow it to show it
320  * as 'raw. Do do that, set argument index
321  * to vendor namespace.
322  */
323  iterator->this_arg_index =
325  if (!iterator->current_namespace)
326  hit = 1;
327  goto next_entry;
329  iterator->_reset_on_ext = 1;
330  iterator->current_namespace = &radiotap_ns;
331  iterator->is_radiotap_ns = 1;
332  goto next_entry;
334  /*
335  * bit 31 was set, there is more
336  * -- move to next u32 bitmap
337  */
338  iterator->_bitmap_shifter =
339  get_unaligned_le32(iterator->_next_bitmap);
340  iterator->_next_bitmap++;
341  if (iterator->_reset_on_ext)
342  iterator->_arg_index = 0;
343  else
344  iterator->_arg_index++;
345  iterator->_reset_on_ext = 0;
346  break;
347  default:
348  /* we've got a hit! */
349  hit = 1;
350  next_entry:
351  iterator->_bitmap_shifter >>= 1;
352  iterator->_arg_index++;
353  }
354 
355  /* if we found a valid arg earlier, return it now */
356  if (hit)
357  return 0;
358  }
359 }