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 140 : 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 140 : if (max_length < (int)sizeof(struct ieee80211_radiotap_header))
97 0 : return -EINVAL;
98 :
99 : /* Linux only supports version 0 radiotap format */
100 140 : if (radiotap_header->it_version)
101 0 : return -EINVAL;
102 :
103 : /* sanity check for allowed length and radiotap length field */
104 140 : if (max_length < get_unaligned_le16(&radiotap_header->it_len))
105 0 : return -EINVAL;
106 :
107 140 : iterator->_rtheader = radiotap_header;
108 140 : iterator->_max_length = get_unaligned_le16(&radiotap_header->it_len);
109 140 : iterator->_arg_index = 0;
110 140 : iterator->_bitmap_shifter = get_unaligned_le32(&radiotap_header->it_present);
111 140 : iterator->_arg = (uint8_t *)radiotap_header + sizeof(*radiotap_header);
112 140 : iterator->_next_ns_data = NULL;
113 140 : iterator->_reset_on_ext = 0;
114 140 : iterator->_next_bitmap = &radiotap_header->it_present;
115 140 : iterator->_next_bitmap++;
116 140 : iterator->_vns = vns;
117 140 : iterator->current_namespace = &radiotap_ns;
118 140 : iterator->is_radiotap_ns = 1;
119 : #ifdef RADIOTAP_SUPPORT_OVERRIDES
120 : iterator->n_overrides = 0;
121 : iterator->overrides = NULL;
122 : #endif
123 :
124 : /* find payload start allowing for extended bitmap(s) */
125 :
126 140 : if (iterator->_bitmap_shifter & BIT(IEEE80211_RADIOTAP_EXT)) {
127 0 : if ((unsigned long)iterator->_arg -
128 0 : (unsigned long)iterator->_rtheader + sizeof(uint32_t) >
129 0 : (unsigned long)iterator->_max_length)
130 0 : return -EINVAL;
131 0 : while (get_unaligned_le32(iterator->_arg) &
132 : BIT(IEEE80211_RADIOTAP_EXT)) {
133 0 : iterator->_arg += sizeof(uint32_t);
134 :
135 : /*
136 : * check for insanity where the present bitmaps
137 : * keep claiming to extend up to or even beyond the
138 : * stated radiotap header length
139 : */
140 :
141 0 : if ((unsigned long)iterator->_arg -
142 0 : (unsigned long)iterator->_rtheader +
143 : sizeof(uint32_t) >
144 0 : (unsigned long)iterator->_max_length)
145 0 : return -EINVAL;
146 : }
147 :
148 0 : iterator->_arg += sizeof(uint32_t);
149 :
150 : /*
151 : * no need to check again for blowing past stated radiotap
152 : * header length, because ieee80211_radiotap_iterator_next
153 : * checks it before it is dereferenced
154 : */
155 : }
156 :
157 140 : iterator->this_arg = iterator->_arg;
158 140 : iterator->this_arg_index = 0;
159 140 : iterator->this_arg_size = 0;
160 :
161 : /* we are all initialized happily */
162 :
163 140 : return 0;
164 : }
165 :
166 0 : static void find_ns(struct ieee80211_radiotap_iterator *iterator,
167 : uint32_t oui, uint8_t subns)
168 : {
169 : int i;
170 :
171 0 : iterator->current_namespace = NULL;
172 :
173 0 : if (!iterator->_vns)
174 0 : return;
175 :
176 0 : for (i = 0; i < iterator->_vns->n_ns; i++) {
177 0 : if (iterator->_vns->ns[i].oui != oui)
178 0 : continue;
179 0 : if (iterator->_vns->ns[i].subns != subns)
180 0 : continue;
181 :
182 0 : iterator->current_namespace = &iterator->_vns->ns[i];
183 0 : break;
184 : }
185 : }
186 :
187 : #ifdef RADIOTAP_SUPPORT_OVERRIDES
188 : static int find_override(struct ieee80211_radiotap_iterator *iterator,
189 : int *align, int *size)
190 : {
191 : int i;
192 :
193 : if (!iterator->overrides)
194 : return 0;
195 :
196 : for (i = 0; i < iterator->n_overrides; i++) {
197 : if (iterator->_arg_index == iterator->overrides[i].field) {
198 : *align = iterator->overrides[i].align;
199 : *size = iterator->overrides[i].size;
200 : if (!*align) /* erroneous override */
201 : return 0;
202 : return 1;
203 : }
204 : }
205 :
206 : return 0;
207 : }
208 : #endif
209 :
210 :
211 : /**
212 : * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg
213 : * @iterator: radiotap_iterator to move to next arg (if any)
214 : *
215 : * Returns: 0 if there is an argument to handle,
216 : * -ENOENT if there are no more args or -EINVAL
217 : * if there is something else wrong.
218 : *
219 : * This function provides the next radiotap arg index (IEEE80211_RADIOTAP_*)
220 : * in @this_arg_index and sets @this_arg to point to the
221 : * payload for the field. It takes care of alignment handling and extended
222 : * present fields. @this_arg can be changed by the caller (eg,
223 : * incremented to move inside a compound argument like
224 : * IEEE80211_RADIOTAP_CHANNEL). The args pointed to are in
225 : * little-endian format whatever the endianess of your CPU.
226 : *
227 : * Alignment Gotcha:
228 : * You must take care when dereferencing iterator.this_arg
229 : * for multibyte types... the pointer is not aligned. Use
230 : * get_unaligned((type *)iterator.this_arg) to dereference
231 : * iterator.this_arg for type "type" safely on all arches.
232 : */
233 :
234 4480 : int ieee80211_radiotap_iterator_next(
235 : struct ieee80211_radiotap_iterator *iterator)
236 : {
237 : while (1) {
238 4480 : int hit = 0;
239 : int pad, align, size, subns;
240 : uint32_t oui;
241 :
242 : /* if no more EXT bits, that's it */
243 4620 : if ((iterator->_arg_index % 32) == IEEE80211_RADIOTAP_EXT &&
244 140 : !(iterator->_bitmap_shifter & 1))
245 140 : return -ENOENT;
246 :
247 4340 : if (!(iterator->_bitmap_shifter & 1))
248 3732 : goto next_entry; /* arg not present */
249 :
250 : /* get alignment/size of data */
251 608 : switch (iterator->_arg_index % 32) {
252 : case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE:
253 : case IEEE80211_RADIOTAP_EXT:
254 0 : align = 1;
255 0 : size = 0;
256 0 : break;
257 : case IEEE80211_RADIOTAP_VENDOR_NAMESPACE:
258 0 : align = 2;
259 0 : size = 6;
260 0 : break;
261 : default:
262 : #ifdef RADIOTAP_SUPPORT_OVERRIDES
263 : if (find_override(iterator, &align, &size)) {
264 : /* all set */
265 : } else
266 : #endif
267 1216 : if (!iterator->current_namespace ||
268 608 : iterator->_arg_index >= iterator->current_namespace->n_bits) {
269 0 : if (iterator->current_namespace == &radiotap_ns)
270 0 : return -ENOENT;
271 0 : align = 0;
272 : } else {
273 608 : align = iterator->current_namespace->align_size[iterator->_arg_index].align;
274 608 : size = iterator->current_namespace->align_size[iterator->_arg_index].size;
275 : }
276 608 : if (!align) {
277 : /* skip all subsequent data */
278 0 : iterator->_arg = iterator->_next_ns_data;
279 : /* give up on this namespace */
280 0 : iterator->current_namespace = NULL;
281 0 : goto next_entry;
282 : }
283 608 : break;
284 : }
285 :
286 : /*
287 : * arg is present, account for alignment padding
288 : *
289 : * Note that these alignments are relative to the start
290 : * of the radiotap header. There is no guarantee
291 : * that the radiotap header itself is aligned on any
292 : * kind of boundary.
293 : *
294 : * The above is why get_unaligned() is used to dereference
295 : * multibyte elements from the radiotap area.
296 : */
297 :
298 1824 : pad = ((unsigned long)iterator->_arg -
299 1216 : (unsigned long)iterator->_rtheader) & (align - 1);
300 :
301 608 : if (pad)
302 94 : iterator->_arg += align - pad;
303 :
304 608 : if (iterator->_arg_index % 32 == IEEE80211_RADIOTAP_VENDOR_NAMESPACE) {
305 : int vnslen;
306 :
307 0 : if ((unsigned long)iterator->_arg + size -
308 0 : (unsigned long)iterator->_rtheader >
309 0 : (unsigned long)iterator->_max_length)
310 0 : return -EINVAL;
311 :
312 0 : oui = (*iterator->_arg << 16) |
313 0 : (*(iterator->_arg + 1) << 8) |
314 0 : *(iterator->_arg + 2);
315 0 : subns = *(iterator->_arg + 3);
316 :
317 0 : find_ns(iterator, oui, subns);
318 :
319 0 : vnslen = get_unaligned_le16(iterator->_arg + 4);
320 0 : iterator->_next_ns_data = iterator->_arg + size + vnslen;
321 0 : if (!iterator->current_namespace)
322 0 : size += vnslen;
323 : }
324 :
325 : /*
326 : * this is what we will return to user, but we need to
327 : * move on first so next call has something fresh to test
328 : */
329 608 : iterator->this_arg_index = iterator->_arg_index;
330 608 : iterator->this_arg = iterator->_arg;
331 608 : iterator->this_arg_size = size;
332 :
333 : /* internally move on the size of this arg */
334 608 : iterator->_arg += size;
335 :
336 : /*
337 : * check for insanity where we are given a bitmap that
338 : * claims to have more arg content than the length of the
339 : * radiotap section. We will normally end up equalling this
340 : * max_length on the last arg, never exceeding it.
341 : */
342 :
343 1824 : if ((unsigned long)iterator->_arg -
344 608 : (unsigned long)iterator->_rtheader >
345 608 : (unsigned long)iterator->_max_length)
346 0 : return -EINVAL;
347 :
348 : /* these special ones are valid in each bitmap word */
349 608 : switch (iterator->_arg_index % 32) {
350 : case IEEE80211_RADIOTAP_VENDOR_NAMESPACE:
351 0 : iterator->_reset_on_ext = 1;
352 :
353 0 : iterator->is_radiotap_ns = 0;
354 : /*
355 : * If parser didn't register this vendor
356 : * namespace with us, allow it to show it
357 : * as 'raw. Do do that, set argument index
358 : * to vendor namespace.
359 : */
360 0 : iterator->this_arg_index =
361 : IEEE80211_RADIOTAP_VENDOR_NAMESPACE;
362 0 : if (!iterator->current_namespace)
363 0 : hit = 1;
364 0 : goto next_entry;
365 : case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE:
366 0 : iterator->_reset_on_ext = 1;
367 0 : iterator->current_namespace = &radiotap_ns;
368 0 : iterator->is_radiotap_ns = 1;
369 0 : goto next_entry;
370 : case IEEE80211_RADIOTAP_EXT:
371 : /*
372 : * bit 31 was set, there is more
373 : * -- move to next u32 bitmap
374 : */
375 0 : iterator->_bitmap_shifter =
376 0 : get_unaligned_le32(iterator->_next_bitmap);
377 0 : iterator->_next_bitmap++;
378 0 : if (iterator->_reset_on_ext)
379 0 : iterator->_arg_index = 0;
380 : else
381 0 : iterator->_arg_index++;
382 0 : iterator->_reset_on_ext = 0;
383 0 : break;
384 : default:
385 : /* we've got a hit! */
386 608 : hit = 1;
387 : next_entry:
388 4340 : iterator->_bitmap_shifter >>= 1;
389 4340 : iterator->_arg_index++;
390 : }
391 :
392 : /* if we found a valid arg earlier, return it now */
393 4340 : if (hit)
394 608 : return 0;
395 3732 : }
396 : }
|