xref: /linux/net/wireless/radiotap.c (revision d39d0ed196aa1685bb24771e92f78633c66ac9cb)
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 
17 #include <net/cfg80211.h>
18 #include <net/ieee80211_radiotap.h>
19 #include <asm/unaligned.h>
20 
21 /* function prototypes and related defs are in include/net/cfg80211.h */
22 
23 static const struct radiotap_align_size rtap_namespace_sizes[] = {
24 	[IEEE80211_RADIOTAP_TSFT] = { .align = 8, .size = 8, },
25 	[IEEE80211_RADIOTAP_FLAGS] = { .align = 1, .size = 1, },
26 	[IEEE80211_RADIOTAP_RATE] = { .align = 1, .size = 1, },
27 	[IEEE80211_RADIOTAP_CHANNEL] = { .align = 2, .size = 4, },
28 	[IEEE80211_RADIOTAP_FHSS] = { .align = 2, .size = 2, },
29 	[IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = { .align = 1, .size = 1, },
30 	[IEEE80211_RADIOTAP_DBM_ANTNOISE] = { .align = 1, .size = 1, },
31 	[IEEE80211_RADIOTAP_LOCK_QUALITY] = { .align = 2, .size = 2, },
32 	[IEEE80211_RADIOTAP_TX_ATTENUATION] = { .align = 2, .size = 2, },
33 	[IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = { .align = 2, .size = 2, },
34 	[IEEE80211_RADIOTAP_DBM_TX_POWER] = { .align = 1, .size = 1, },
35 	[IEEE80211_RADIOTAP_ANTENNA] = { .align = 1, .size = 1, },
36 	[IEEE80211_RADIOTAP_DB_ANTSIGNAL] = { .align = 1, .size = 1, },
37 	[IEEE80211_RADIOTAP_DB_ANTNOISE] = { .align = 1, .size = 1, },
38 	[IEEE80211_RADIOTAP_RX_FLAGS] = { .align = 2, .size = 2, },
39 	[IEEE80211_RADIOTAP_TX_FLAGS] = { .align = 2, .size = 2, },
40 	[IEEE80211_RADIOTAP_RTS_RETRIES] = { .align = 1, .size = 1, },
41 	[IEEE80211_RADIOTAP_DATA_RETRIES] = { .align = 1, .size = 1, },
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:
88  * See Documentation/networking/radiotap-headers.txt
89  */
90 
91 int ieee80211_radiotap_iterator_init(
92 	struct ieee80211_radiotap_iterator *iterator,
93 	struct ieee80211_radiotap_header *radiotap_header,
94 	int max_length, const struct ieee80211_radiotap_vendor_namespaces *vns)
95 {
96 	/* Linux only supports version 0 radiotap format */
97 	if (radiotap_header->it_version)
98 		return -EINVAL;
99 
100 	/* sanity check for allowed length and radiotap length field */
101 	if (max_length < get_unaligned_le16(&radiotap_header->it_len))
102 		return -EINVAL;
103 
104 	iterator->_rtheader = radiotap_header;
105 	iterator->_max_length = get_unaligned_le16(&radiotap_header->it_len);
106 	iterator->_arg_index = 0;
107 	iterator->_bitmap_shifter = get_unaligned_le32(&radiotap_header->it_present);
108 	iterator->_arg = (uint8_t *)radiotap_header + sizeof(*radiotap_header);
109 	iterator->_reset_on_ext = 0;
110 	iterator->_next_bitmap = &radiotap_header->it_present;
111 	iterator->_next_bitmap++;
112 	iterator->_vns = vns;
113 	iterator->current_namespace = &radiotap_ns;
114 	iterator->is_radiotap_ns = 1;
115 
116 	/* find payload start allowing for extended bitmap(s) */
117 
118 	if (iterator->_bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT)) {
119 		while (get_unaligned_le32(iterator->_arg) &
120 					(1 << IEEE80211_RADIOTAP_EXT)) {
121 			iterator->_arg += sizeof(uint32_t);
122 
123 			/*
124 			 * check for insanity where the present bitmaps
125 			 * keep claiming to extend up to or even beyond the
126 			 * stated radiotap header length
127 			 */
128 
129 			if ((unsigned long)iterator->_arg -
130 			    (unsigned long)iterator->_rtheader >
131 			    (unsigned long)iterator->_max_length)
132 				return -EINVAL;
133 		}
134 
135 		iterator->_arg += sizeof(uint32_t);
136 
137 		/*
138 		 * no need to check again for blowing past stated radiotap
139 		 * header length, because ieee80211_radiotap_iterator_next
140 		 * checks it before it is dereferenced
141 		 */
142 	}
143 
144 	iterator->this_arg = iterator->_arg;
145 
146 	/* we are all initialized happily */
147 
148 	return 0;
149 }
150 EXPORT_SYMBOL(ieee80211_radiotap_iterator_init);
151 
152 static void find_ns(struct ieee80211_radiotap_iterator *iterator,
153 		    uint32_t oui, uint8_t subns)
154 {
155 	int i;
156 
157 	iterator->current_namespace = NULL;
158 
159 	if (!iterator->_vns)
160 		return;
161 
162 	for (i = 0; i < iterator->_vns->n_ns; i++) {
163 		if (iterator->_vns->ns[i].oui != oui)
164 			continue;
165 		if (iterator->_vns->ns[i].subns != subns)
166 			continue;
167 
168 		iterator->current_namespace = &iterator->_vns->ns[i];
169 		break;
170 	}
171 }
172 
173 
174 
175 /**
176  * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg
177  * @iterator: radiotap_iterator to move to next arg (if any)
178  *
179  * Returns: 0 if there is an argument to handle,
180  * -ENOENT if there are no more args or -EINVAL
181  * if there is something else wrong.
182  *
183  * This function provides the next radiotap arg index (IEEE80211_RADIOTAP_*)
184  * in @this_arg_index and sets @this_arg to point to the
185  * payload for the field.  It takes care of alignment handling and extended
186  * present fields.  @this_arg can be changed by the caller (eg,
187  * incremented to move inside a compound argument like
188  * IEEE80211_RADIOTAP_CHANNEL).  The args pointed to are in
189  * little-endian format whatever the endianess of your CPU.
190  *
191  * Alignment Gotcha:
192  * You must take care when dereferencing iterator.this_arg
193  * for multibyte types... the pointer is not aligned.  Use
194  * get_unaligned((type *)iterator.this_arg) to dereference
195  * iterator.this_arg for type "type" safely on all arches.
196  */
197 
198 int ieee80211_radiotap_iterator_next(
199 	struct ieee80211_radiotap_iterator *iterator)
200 {
201 	while (1) {
202 		int hit = 0;
203 		int pad, align, size, subns, vnslen;
204 		uint32_t oui;
205 
206 		/* if no more EXT bits, that's it */
207 		if ((iterator->_arg_index % 32) == IEEE80211_RADIOTAP_EXT &&
208 		    !(iterator->_bitmap_shifter & 1))
209 			return -ENOENT;
210 
211 		if (!(iterator->_bitmap_shifter & 1))
212 			goto next_entry; /* arg not present */
213 
214 		/* get alignment/size of data */
215 		switch (iterator->_arg_index % 32) {
216 		case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE:
217 		case IEEE80211_RADIOTAP_EXT:
218 			align = 1;
219 			size = 0;
220 			break;
221 		case IEEE80211_RADIOTAP_VENDOR_NAMESPACE:
222 			align = 2;
223 			size = 6;
224 			break;
225 		default:
226 			if (!iterator->current_namespace ||
227 			    iterator->_arg_index >= iterator->current_namespace->n_bits) {
228 				if (iterator->current_namespace == &radiotap_ns)
229 					return -ENOENT;
230 				align = 0;
231 			} else {
232 				align = iterator->current_namespace->align_size[iterator->_arg_index].align;
233 				size = iterator->current_namespace->align_size[iterator->_arg_index].size;
234 			}
235 			if (!align) {
236 				/* skip all subsequent data */
237 				iterator->_arg = iterator->_next_ns_data;
238 				/* give up on this namespace */
239 				iterator->current_namespace = NULL;
240 				goto next_entry;
241 			}
242 			break;
243 		}
244 
245 		/*
246 		 * arg is present, account for alignment padding
247 		 *
248 		 * Note that these alignments are relative to the start
249 		 * of the radiotap header.  There is no guarantee
250 		 * that the radiotap header itself is aligned on any
251 		 * kind of boundary.
252 		 *
253 		 * The above is why get_unaligned() is used to dereference
254 		 * multibyte elements from the radiotap area.
255 		 */
256 
257 		pad = ((unsigned long)iterator->_arg -
258 		       (unsigned long)iterator->_rtheader) & (align - 1);
259 
260 		if (pad)
261 			iterator->_arg += align - pad;
262 
263 		/*
264 		 * this is what we will return to user, but we need to
265 		 * move on first so next call has something fresh to test
266 		 */
267 		iterator->this_arg_index = iterator->_arg_index;
268 		iterator->this_arg = iterator->_arg;
269 		iterator->this_arg_size = size;
270 
271 		/* internally move on the size of this arg */
272 		iterator->_arg += size;
273 
274 		/*
275 		 * check for insanity where we are given a bitmap that
276 		 * claims to have more arg content than the length of the
277 		 * radiotap section.  We will normally end up equalling this
278 		 * max_length on the last arg, never exceeding it.
279 		 */
280 
281 		if ((unsigned long)iterator->_arg -
282 		    (unsigned long)iterator->_rtheader >
283 		    (unsigned long)iterator->_max_length)
284 			return -EINVAL;
285 
286 		/* these special ones are valid in each bitmap word */
287 		switch (iterator->_arg_index % 32) {
288 		case IEEE80211_RADIOTAP_VENDOR_NAMESPACE:
289 			iterator->_bitmap_shifter >>= 1;
290 			iterator->_arg_index++;
291 
292 			iterator->_reset_on_ext = 1;
293 
294 			vnslen = get_unaligned_le16(iterator->this_arg + 4);
295 			iterator->_next_ns_data = iterator->_arg + vnslen;
296 			oui = (*iterator->this_arg << 16) |
297 				(*(iterator->this_arg + 1) << 8) |
298 				*(iterator->this_arg + 2);
299 			subns = *(iterator->this_arg + 3);
300 
301 			find_ns(iterator, oui, subns);
302 
303 			iterator->is_radiotap_ns = 0;
304 			/* allow parsers to show this information */
305 			iterator->this_arg_index =
306 				IEEE80211_RADIOTAP_VENDOR_NAMESPACE;
307 			iterator->this_arg_size += vnslen;
308 			if ((unsigned long)iterator->this_arg +
309 			    iterator->this_arg_size -
310 			    (unsigned long)iterator->_rtheader >
311 			    (unsigned long)(unsigned long)iterator->_max_length)
312 				return -EINVAL;
313 			hit = 1;
314 			break;
315 		case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE:
316 			iterator->_bitmap_shifter >>= 1;
317 			iterator->_arg_index++;
318 
319 			iterator->_reset_on_ext = 1;
320 			iterator->current_namespace = &radiotap_ns;
321 			iterator->is_radiotap_ns = 1;
322 			break;
323 		case IEEE80211_RADIOTAP_EXT:
324 			/*
325 			 * bit 31 was set, there is more
326 			 * -- move to next u32 bitmap
327 			 */
328 			iterator->_bitmap_shifter =
329 				get_unaligned_le32(iterator->_next_bitmap);
330 			iterator->_next_bitmap++;
331 			if (iterator->_reset_on_ext)
332 				iterator->_arg_index = 0;
333 			else
334 				iterator->_arg_index++;
335 			iterator->_reset_on_ext = 0;
336 			break;
337 		default:
338 			/* we've got a hit! */
339 			hit = 1;
340  next_entry:
341 			iterator->_bitmap_shifter >>= 1;
342 			iterator->_arg_index++;
343 		}
344 
345 		/* if we found a valid arg earlier, return it now */
346 		if (hit)
347 			return 0;
348 	}
349 }
350 EXPORT_SYMBOL(ieee80211_radiotap_iterator_next);
351