1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
24
25static 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
48
49};
50
51static const struct ieee80211_radiotap_namespace radiotap_ns = {
52 .n_bits = ARRAY_SIZE(rtap_namespace_sizes),
53 .align_size = rtap_namespace_sizes,
54};
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95int ieee80211_radiotap_iterator_init(
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
101 if (radiotap_header->it_version)
102 return -EINVAL;
103
104
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
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
129
130
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
143
144
145
146 }
147
148 iterator->this_arg = iterator->_arg;
149
150
151
152 return 0;
153}
154EXPORT_SYMBOL(ieee80211_radiotap_iterator_init);
155
156static void find_ns(struct ieee80211_radiotap_iterator *iterator,
157 uint32_t oui, uint8_t subns)
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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202int ieee80211_radiotap_iterator_next(
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
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;
217
218
219 switch (iterator->_arg_index % 32) {
220 case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE:
221 case IEEE80211_RADIOTAP_EXT:
222 align = 1;
223 size = 0;
224 break;
225 case IEEE80211_RADIOTAP_VENDOR_NAMESPACE:
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
241 iterator->_arg = iterator->_next_ns_data;
242
243 iterator->current_namespace = NULL;
244 goto next_entry;
245 }
246 break;
247 }
248
249
250
251
252
253
254
255
256
257
258
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
290
291
292 iterator->this_arg_index = iterator->_arg_index;
293 iterator->this_arg = iterator->_arg;
294 iterator->this_arg_size = size;
295
296
297 iterator->_arg += size;
298
299
300
301
302
303
304
305
306 if ((unsigned long)iterator->_arg -
307 (unsigned long)iterator->_rtheader >
308 (unsigned long)iterator->_max_length)
309 return -EINVAL;
310
311
312 switch (iterator->_arg_index % 32) {
313 case IEEE80211_RADIOTAP_VENDOR_NAMESPACE:
314 iterator->_reset_on_ext = 1;
315
316 iterator->is_radiotap_ns = 0;
317
318
319
320
321
322
323 iterator->this_arg_index =
324 IEEE80211_RADIOTAP_VENDOR_NAMESPACE;
325 if (!iterator->current_namespace)
326 hit = 1;
327 goto next_entry;
328 case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE:
329 iterator->_reset_on_ext = 1;
330 iterator->current_namespace = &radiotap_ns;
331 iterator->is_radiotap_ns = 1;
332 goto next_entry;
333 case IEEE80211_RADIOTAP_EXT:
334
335
336
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
349 hit = 1;
350 next_entry:
351 iterator->_bitmap_shifter >>= 1;
352 iterator->_arg_index++;
353 }
354
355
356 if (hit)
357 return 0;
358 }
359}
360EXPORT_SYMBOL(ieee80211_radiotap_iterator_next);
361