Line data Source code
1 : /*
2 : * Radiotap parser
3 : *
4 : * Copyright 2007 Andy Green <andy@warmcat.com>
5 : * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
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 : #include "radiotap_iter.h"
17 : #include "platform.h"
18 :
19 : /* function prototypes and related defs are in radiotap_iter.h */
20 :
21 : static const struct radiotap_align_size rtap_namespace_sizes[] = {
22 : [IEEE80211_RADIOTAP_TSFT] = { .align = 8, .size = 8, },
23 : [IEEE80211_RADIOTAP_FLAGS] = { .align = 1, .size = 1, },
24 : [IEEE80211_RADIOTAP_RATE] = { .align = 1, .size = 1, },
25 : [IEEE80211_RADIOTAP_CHANNEL] = { .align = 2, .size = 4, },
26 : [IEEE80211_RADIOTAP_FHSS] = { .align = 2, .size = 2, },
27 : [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = { .align = 1, .size = 1, },
28 : [IEEE80211_RADIOTAP_DBM_ANTNOISE] = { .align = 1, .size = 1, },
29 : [IEEE80211_RADIOTAP_LOCK_QUALITY] = { .align = 2, .size = 2, },
30 : [IEEE80211_RADIOTAP_TX_ATTENUATION] = { .align = 2, .size = 2, },
31 : [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = { .align = 2, .size = 2, },
32 : [IEEE80211_RADIOTAP_DBM_TX_POWER] = { .align = 1, .size = 1, },
33 : [IEEE80211_RADIOTAP_ANTENNA] = { .align = 1, .size = 1, },
34 : [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = { .align = 1, .size = 1, },
35 : [IEEE80211_RADIOTAP_DB_ANTNOISE] = { .align = 1, .size = 1, },
36 : [IEEE80211_RADIOTAP_RX_FLAGS] = { .align = 2, .size = 2, },
37 : [IEEE80211_RADIOTAP_TX_FLAGS] = { .align = 2, .size = 2, },
38 : [IEEE80211_RADIOTAP_RTS_RETRIES] = { .align = 1, .size = 1, },
39 : [IEEE80211_RADIOTAP_DATA_RETRIES] = { .align = 1, .size = 1, },
40 : [IEEE80211_RADIOTAP_MCS] = { .align = 1, .size = 3, },
41 : [IEEE80211_RADIOTAP_AMPDU_STATUS] = { .align = 4, .size = 8, },
42 : /*
43 : * add more here as they are defined in radiotap.h
44 : */
45 : };
46 :
47 : static const struct ieee80211_radiotap_namespace radiotap_ns = {
48 : .n_bits = sizeof(rtap_namespace_sizes) / sizeof(rtap_namespace_sizes[0]),
49 : .align_size = rtap_namespace_sizes,
50 : };
51 :
52 : /**
53 : * ieee80211_radiotap_iterator_init - radiotap parser iterator initialization
54 : * @iterator: radiotap_iterator to initialize
55 : * @radiotap_header: radiotap header to parse
56 : * @max_length: total length we can parse into (eg, whole packet length)
57 : *
58 : * Returns: 0 or a negative error code if there is a problem.
59 : *
60 : * This function initializes an opaque iterator struct which can then
61 : * be passed to ieee80211_radiotap_iterator_next() to visit every radiotap
62 : * argument which is present in the header. It knows about extended
63 : * present headers and handles them.
64 : *
65 : * How to use:
66 : * call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator
67 : * struct ieee80211_radiotap_iterator (no need to init the struct beforehand)
68 : * checking for a good 0 return code. Then loop calling
69 : * __ieee80211_radiotap_iterator_next()... it returns either 0,
70 : * -ENOENT if there are no more args to parse, or -EINVAL if there is a problem.
71 : * The iterator's @this_arg member points to the start of the argument
72 : * associated with the current argument index that is present, which can be
73 : * found in the iterator's @this_arg_index member. This arg index corresponds
74 : * to the IEEE80211_RADIOTAP_... defines.
75 : *
76 : * Radiotap header length:
77 : * You can find the CPU-endian total radiotap header length in
78 : * iterator->max_length after executing ieee80211_radiotap_iterator_init()
79 : * successfully.
80 : *
81 : * Alignment Gotcha:
82 : * You must take care when dereferencing iterator.this_arg
83 : * for multibyte types... the pointer is not aligned. Use
84 : * get_unaligned((type *)iterator.this_arg) to dereference
85 : * iterator.this_arg for type "type" safely on all arches.
86 : *
87 : * Example code: parse.c
88 : */
89 :
90 31 : int ieee80211_radiotap_iterator_init(
91 : struct ieee80211_radiotap_iterator *iterator,
92 : struct ieee80211_radiotap_header *radiotap_header,
93 : int max_length, const struct ieee80211_radiotap_vendor_namespaces *vns)
94 : {
95 : /* must at least have the radiotap header */
96 31 : if (max_length < (int)sizeof(struct ieee80211_radiotap_header))
97 0 : return -EINVAL;
98 :
99 : /* Linux only supports version 0 radiotap format */
100 31 : if (radiotap_header->it_version)
101 0 : return -EINVAL;
102 :
103 : /* sanity check for allowed length and radiotap length field */
104 31 : if (max_length < get_unaligned_le16(&radiotap_header->it_len))
105 0 : return -EINVAL;
106 :
107 31 : iterator->_rtheader = radiotap_header;
108 31 : iterator->_max_length = get_unaligned_le16(&radiotap_header->it_len);
109 31 : iterator->_arg_index = 0;
110 31 : iterator->_bitmap_shifter = get_unaligned_le32(&radiotap_header->it_present);
111 31 : iterator->_arg = (uint8_t *)radiotap_header + sizeof(*radiotap_header);
112 31 : iterator->_reset_on_ext = 0;
113 31 : iterator->_next_bitmap = &radiotap_header->it_present;
114 31 : iterator->_next_bitmap++;
115 31 : iterator->_vns = vns;
116 31 : iterator->current_namespace = &radiotap_ns;
117 31 : iterator->is_radiotap_ns = 1;
118 : #ifdef RADIOTAP_SUPPORT_OVERRIDES
119 : iterator->n_overrides = 0;
120 : iterator->overrides = NULL;
121 : #endif
122 :
123 : /* find payload start allowing for extended bitmap(s) */
124 :
125 31 : if (iterator->_bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT)) {
126 0 : if ((unsigned long)iterator->_arg -
127 0 : (unsigned long)iterator->_rtheader + sizeof(uint32_t) >
128 0 : (unsigned long)iterator->_max_length)
129 0 : return -EINVAL;
130 0 : while (get_unaligned_le32(iterator->_arg) &
131 : (1 << IEEE80211_RADIOTAP_EXT)) {
132 0 : iterator->_arg += sizeof(uint32_t);
133 :
134 : /*
135 : * check for insanity where the present bitmaps
136 : * keep claiming to extend up to or even beyond the
137 : * stated radiotap header length
138 : */
139 :
140 0 : if ((unsigned long)iterator->_arg -
141 0 : (unsigned long)iterator->_rtheader +
142 : sizeof(uint32_t) >
143 0 : (unsigned long)iterator->_max_length)
144 0 : return -EINVAL;
145 : }
146 :
147 0 : iterator->_arg += sizeof(uint32_t);
148 :
149 : /*
150 : * no need to check again for blowing past stated radiotap
151 : * header length, because ieee80211_radiotap_iterator_next
152 : * checks it before it is dereferenced
153 : */
154 : }
155 :
156 31 : iterator->this_arg = iterator->_arg;
157 :
158 : /* we are all initialized happily */
159 :
160 31 : return 0;
161 : }
162 :
163 0 : static void find_ns(struct ieee80211_radiotap_iterator *iterator,
164 : uint32_t oui, uint8_t subns)
165 : {
166 : int i;
167 :
168 0 : iterator->current_namespace = NULL;
169 :
170 0 : if (!iterator->_vns)
171 0 : return;
172 :
173 0 : for (i = 0; i < iterator->_vns->n_ns; i++) {
174 0 : if (iterator->_vns->ns[i].oui != oui)
175 0 : continue;
176 0 : if (iterator->_vns->ns[i].subns != subns)
177 0 : continue;
178 :
179 0 : iterator->current_namespace = &iterator->_vns->ns[i];
180 0 : break;
181 : }
182 : }
183 :
184 : #ifdef RADIOTAP_SUPPORT_OVERRIDES
185 : static int find_override(struct ieee80211_radiotap_iterator *iterator,
186 : int *align, int *size)
187 : {
188 : int i;
189 :
190 : if (!iterator->overrides)
191 : return 0;
192 :
193 : for (i = 0; i < iterator->n_overrides; i++) {
194 : if (iterator->_arg_index == iterator->overrides[i].field) {
195 : *align = iterator->overrides[i].align;
196 : *size = iterator->overrides[i].size;
197 : if (!*align) /* erroneous override */
198 : return 0;
199 : return 1;
200 : }
201 : }
202 :
203 : return 0;
204 : }
205 : #endif
206 :
207 :
208 : /**
209 : * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg
210 : * @iterator: radiotap_iterator to move to next arg (if any)
211 : *
212 : * Returns: 0 if there is an argument to handle,
213 : * -ENOENT if there are no more args or -EINVAL
214 : * if there is something else wrong.
215 : *
216 : * This function provides the next radiotap arg index (IEEE80211_RADIOTAP_*)
217 : * in @this_arg_index and sets @this_arg to point to the
218 : * payload for the field. It takes care of alignment handling and extended
219 : * present fields. @this_arg can be changed by the caller (eg,
220 : * incremented to move inside a compound argument like
221 : * IEEE80211_RADIOTAP_CHANNEL). The args pointed to are in
222 : * little-endian format whatever the endianess of your CPU.
223 : *
224 : * Alignment Gotcha:
225 : * You must take care when dereferencing iterator.this_arg
226 : * for multibyte types... the pointer is not aligned. Use
227 : * get_unaligned((type *)iterator.this_arg) to dereference
228 : * iterator.this_arg for type "type" safely on all arches.
229 : */
230 :
231 992 : int ieee80211_radiotap_iterator_next(
232 : struct ieee80211_radiotap_iterator *iterator)
233 : {
234 : while (1) {
235 992 : int hit = 0;
236 : int pad, align, size, subns;
237 : uint32_t oui;
238 :
239 : /* if no more EXT bits, that's it */
240 1023 : if ((iterator->_arg_index % 32) == IEEE80211_RADIOTAP_EXT &&
241 31 : !(iterator->_bitmap_shifter & 1))
242 31 : return -ENOENT;
243 :
244 961 : if (!(iterator->_bitmap_shifter & 1))
245 816 : goto next_entry; /* arg not present */
246 :
247 : /* get alignment/size of data */
248 145 : switch (iterator->_arg_index % 32) {
249 : case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE:
250 : case IEEE80211_RADIOTAP_EXT:
251 0 : align = 1;
252 0 : size = 0;
253 0 : break;
254 : case IEEE80211_RADIOTAP_VENDOR_NAMESPACE:
255 0 : align = 2;
256 0 : size = 6;
257 0 : break;
258 : default:
259 : #ifdef RADIOTAP_SUPPORT_OVERRIDES
260 : if (find_override(iterator, &align, &size)) {
261 : /* all set */
262 : } else
263 : #endif
264 290 : if (!iterator->current_namespace ||
265 145 : iterator->_arg_index >= iterator->current_namespace->n_bits) {
266 0 : if (iterator->current_namespace == &radiotap_ns)
267 0 : return -ENOENT;
268 0 : align = 0;
269 : } else {
270 145 : align = iterator->current_namespace->align_size[iterator->_arg_index].align;
271 145 : size = iterator->current_namespace->align_size[iterator->_arg_index].size;
272 : }
273 145 : if (!align) {
274 : /* skip all subsequent data */
275 0 : iterator->_arg = iterator->_next_ns_data;
276 : /* give up on this namespace */
277 0 : iterator->current_namespace = NULL;
278 0 : goto next_entry;
279 : }
280 145 : break;
281 : }
282 :
283 : /*
284 : * arg is present, account for alignment padding
285 : *
286 : * Note that these alignments are relative to the start
287 : * of the radiotap header. There is no guarantee
288 : * that the radiotap header itself is aligned on any
289 : * kind of boundary.
290 : *
291 : * The above is why get_unaligned() is used to dereference
292 : * multibyte elements from the radiotap area.
293 : */
294 :
295 435 : pad = ((unsigned long)iterator->_arg -
296 290 : (unsigned long)iterator->_rtheader) & (align - 1);
297 :
298 145 : if (pad)
299 14 : iterator->_arg += align - pad;
300 :
301 145 : if (iterator->_arg_index % 32 == IEEE80211_RADIOTAP_VENDOR_NAMESPACE) {
302 : int vnslen;
303 :
304 0 : if ((unsigned long)iterator->_arg + size -
305 0 : (unsigned long)iterator->_rtheader >
306 0 : (unsigned long)iterator->_max_length)
307 0 : return -EINVAL;
308 :
309 0 : oui = (*iterator->_arg << 16) |
310 0 : (*(iterator->_arg + 1) << 8) |
311 0 : *(iterator->_arg + 2);
312 0 : subns = *(iterator->_arg + 3);
313 :
314 0 : find_ns(iterator, oui, subns);
315 :
316 0 : vnslen = get_unaligned_le16(iterator->_arg + 4);
317 0 : iterator->_next_ns_data = iterator->_arg + size + vnslen;
318 0 : if (!iterator->current_namespace)
319 0 : size += vnslen;
320 : }
321 :
322 : /*
323 : * this is what we will return to user, but we need to
324 : * move on first so next call has something fresh to test
325 : */
326 145 : iterator->this_arg_index = iterator->_arg_index;
327 145 : iterator->this_arg = iterator->_arg;
328 145 : iterator->this_arg_size = size;
329 :
330 : /* internally move on the size of this arg */
331 145 : iterator->_arg += size;
332 :
333 : /*
334 : * check for insanity where we are given a bitmap that
335 : * claims to have more arg content than the length of the
336 : * radiotap section. We will normally end up equalling this
337 : * max_length on the last arg, never exceeding it.
338 : */
339 :
340 435 : if ((unsigned long)iterator->_arg -
341 145 : (unsigned long)iterator->_rtheader >
342 145 : (unsigned long)iterator->_max_length)
343 0 : return -EINVAL;
344 :
345 : /* these special ones are valid in each bitmap word */
346 145 : switch (iterator->_arg_index % 32) {
347 : case IEEE80211_RADIOTAP_VENDOR_NAMESPACE:
348 0 : iterator->_reset_on_ext = 1;
349 :
350 0 : iterator->is_radiotap_ns = 0;
351 : /*
352 : * If parser didn't register this vendor
353 : * namespace with us, allow it to show it
354 : * as 'raw. Do do that, set argument index
355 : * to vendor namespace.
356 : */
357 0 : iterator->this_arg_index =
358 : IEEE80211_RADIOTAP_VENDOR_NAMESPACE;
359 0 : if (!iterator->current_namespace)
360 0 : hit = 1;
361 0 : goto next_entry;
362 : case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE:
363 0 : iterator->_reset_on_ext = 1;
364 0 : iterator->current_namespace = &radiotap_ns;
365 0 : iterator->is_radiotap_ns = 1;
366 0 : goto next_entry;
367 : case IEEE80211_RADIOTAP_EXT:
368 : /*
369 : * bit 31 was set, there is more
370 : * -- move to next u32 bitmap
371 : */
372 0 : iterator->_bitmap_shifter =
373 0 : get_unaligned_le32(iterator->_next_bitmap);
374 0 : iterator->_next_bitmap++;
375 0 : if (iterator->_reset_on_ext)
376 0 : iterator->_arg_index = 0;
377 : else
378 0 : iterator->_arg_index++;
379 0 : iterator->_reset_on_ext = 0;
380 0 : break;
381 : default:
382 : /* we've got a hit! */
383 145 : hit = 1;
384 : next_entry:
385 961 : iterator->_bitmap_shifter >>= 1;
386 961 : iterator->_arg_index++;
387 : }
388 :
389 : /* if we found a valid arg earlier, return it now */
390 961 : if (hit)
391 145 : return 0;
392 816 : }
393 : }
|