binding to specific address
[oweals/gnunet.git] / src / transport / wlan / radiotap-parser.c
1  /*
2   *  Copyright (c) 2007, 2008, Andy Green <andy@warmcat.com>
3   *
4   *  This program is free software; you can redistribute it and/or modify
5   *  it under the terms of the GNU General Public License as published by
6   *  the Free Software Foundation; either version 2 of the License, or
7   *  (at your option) any later version.
8   *
9   *  This program is distributed in the hope that it will be useful,
10   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   *  GNU General Public License for more details.
13   *
14   *  You should have received a copy of the GNU General Public License
15   *  along with this program; if not, write to the Free Software
16   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17   */
18
19 #include <sys/types.h>
20 #include <stdio.h>
21 #include <errno.h>
22
23 #include "radiotap-parser.h"
24
25
26 /*
27  * Radiotap header iteration
28  *   implemented in src/radiotap-parser.c
29  *
30  * call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator
31  * struct ieee80211_radiotap_iterator (no need to init the struct beforehand)
32  * then loop calling __ieee80211_radiotap_iterator_next()... it returns -1
33  * if there are no more args in the header, or the next argument type index
34  * that is present.  The iterator's this_arg member points to the start of the
35  * argument associated with the current argument index that is present,
36  * which can be found in the iterator's this_arg_index member.  This arg
37  * index corresponds to the IEEE80211_RADIOTAP_... defines.
38  */
39
40
41 int
42 ieee80211_radiotap_iterator_init (struct ieee80211_radiotap_iterator *iterator,
43                                   struct ieee80211_radiotap_header
44                                   *radiotap_header, int max_length)
45 {
46   if (iterator == NULL)
47     return (-EINVAL);
48
49   if (radiotap_header == NULL)
50     return (-EINVAL);
51   /* Linux only supports version 0 radiotap format */
52
53   if (radiotap_header->it_version)
54     return (-EINVAL);
55
56   /* sanity check for allowed length and radiotap length field */
57
58   if (max_length < (le16_to_cpu (radiotap_header->it_len)))
59     return (-EINVAL);
60
61   iterator->rtheader = radiotap_header;
62   iterator->max_length = le16_to_cpu (radiotap_header->it_len);
63   iterator->arg_index = 0;
64   iterator->bitmap_shifter = le32_to_cpu (radiotap_header->it_present);
65   iterator->arg =
66       ((u8 *) radiotap_header) + sizeof (struct ieee80211_radiotap_header);
67   iterator->this_arg = 0;
68
69   /* find payload start allowing for extended bitmap(s) */
70
71   if (unlikely
72       (iterator->bitmap_shifter & IEEE80211_RADIOTAP_PRESENT_EXTEND_MASK))
73   {
74     while (le32_to_cpu (*((u32 *) iterator->arg)) &
75            IEEE80211_RADIOTAP_PRESENT_EXTEND_MASK)
76     {
77       iterator->arg += sizeof (u32);
78
79       /*
80        * check for insanity where the present bitmaps
81        * keep claiming to extend up to or even beyond the
82        * stated radiotap header length
83        */
84
85       if ((((void *) iterator->arg) - ((void *) iterator->rtheader)) >
86           iterator->max_length)
87         return (-EINVAL);
88
89     }
90
91     iterator->arg += sizeof (u32);
92
93     /*
94      * no need to check again for blowing past stated radiotap
95      * header length, becuase ieee80211_radiotap_iterator_next
96      * checks it before it is dereferenced
97      */
98
99   }
100
101   /* we are all initialized happily */
102
103   return (0);
104 }
105
106
107 /**
108  * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg
109  * @iterator: radiotap_iterator to move to next arg (if any)
110  *
111  * Returns: next present arg index on success or negative if no more or error
112  *
113  * This function returns the next radiotap arg index (IEEE80211_RADIOTAP_...)
114  * and sets iterator->this_arg to point to the payload for the arg.  It takes
115  * care of alignment handling and extended present fields.  interator->this_arg
116  * can be changed by the caller.  The args pointed to are in little-endian
117  * format.
118  */
119
120 int
121 ieee80211_radiotap_iterator_next (struct ieee80211_radiotap_iterator *iterator)
122 {
123
124   /*
125    * small length lookup table for all radiotap types we heard of
126    * starting from b0 in the bitmap, so we can walk the payload
127    * area of the radiotap header
128    *
129    * There is a requirement to pad args, so that args
130    * of a given length must begin at a boundary of that length
131    * -- but note that compound args are allowed (eg, 2 x u16
132    * for IEEE80211_RADIOTAP_CHANNEL) so total arg length is not
133    * a reliable indicator of alignment requirement.
134    *
135    * upper nybble: content alignment for arg
136    * lower nybble: content length for arg
137    */
138
139   static const u8 rt_sizes[] = {
140     [IEEE80211_RADIOTAP_TSFT] = 0x88,
141     [IEEE80211_RADIOTAP_FLAGS] = 0x11,
142     [IEEE80211_RADIOTAP_RATE] = 0x11,
143     [IEEE80211_RADIOTAP_CHANNEL] = 0x24,
144     [IEEE80211_RADIOTAP_FHSS] = 0x22,
145     [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = 0x11,
146     [IEEE80211_RADIOTAP_DBM_ANTNOISE] = 0x11,
147     [IEEE80211_RADIOTAP_LOCK_QUALITY] = 0x22,
148     [IEEE80211_RADIOTAP_TX_ATTENUATION] = 0x22,
149     [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = 0x22,
150     [IEEE80211_RADIOTAP_DBM_TX_POWER] = 0x11,
151     [IEEE80211_RADIOTAP_ANTENNA] = 0x11,
152     [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = 0x11,
153     [IEEE80211_RADIOTAP_DB_ANTNOISE] = 0x11,
154     [IEEE80211_RADIOTAP_TX_FLAGS] = 0x22,
155     [IEEE80211_RADIOTAP_RX_FLAGS] = 0x22,
156     [IEEE80211_RADIOTAP_RTS_RETRIES] = 0x11,
157     [IEEE80211_RADIOTAP_DATA_RETRIES] = 0x11
158         /*
159          * add more here as they are defined in
160          * include/net/ieee80211_radiotap.h
161          */
162   };
163
164   /*
165    * for every radiotap entry we can at
166    * least skip (by knowing the length)...
167    */
168
169   while (iterator->arg_index < (int) sizeof (rt_sizes))
170   {
171     int hit = 0;
172
173     if (!(iterator->bitmap_shifter & 1))
174       goto next_entry;          /* arg not present */
175
176     /*
177      * arg is present, account for alignment padding
178      *  8-bit args can be at any alignment
179      * 16-bit args must start on 16-bit boundary
180      * 32-bit args must start on 32-bit boundary
181      * 64-bit args must start on 64-bit boundary
182      *
183      * note that total arg size can differ from alignment of
184      * elements inside arg, so we use upper nybble of length
185      * table to base alignment on
186      *
187      * also note: these alignments are ** relative to the
188      * start of the radiotap header **.  There is no guarantee
189      * that the radiotap header itself is aligned on any
190      * kind of boundary.
191      */
192
193     if ((((void *) iterator->arg) -
194          ((void *) iterator->rtheader)) & ((rt_sizes[iterator->arg_index] >> 4)
195                                            - 1))
196       iterator->arg_index +=
197           (rt_sizes[iterator->arg_index] >> 4) -
198           ((((void *) iterator->arg) -
199             ((void *) iterator->rtheader)) & ((rt_sizes[iterator->arg_index] >>
200                                                4) - 1));
201
202     /*
203      * this is what we will return to user, but we need to
204      * move on first so next call has something fresh to test
205      */
206
207     iterator->this_arg_index = iterator->arg_index;
208     iterator->this_arg = iterator->arg;
209     hit = 1;
210
211     /* internally move on the size of this arg */
212
213     iterator->arg += rt_sizes[iterator->arg_index] & 0x0f;
214
215     /*
216      * check for insanity where we are given a bitmap that
217      * claims to have more arg content than the length of the
218      * radiotap section.  We will normally end up equalling this
219      * max_length on the last arg, never exceeding it.
220      */
221
222     if ((((void *) iterator->arg) - ((void *) iterator->rtheader)) >
223         iterator->max_length)
224       return (-EINVAL);
225
226 next_entry:
227
228     iterator->arg_index++;
229     if (unlikely ((iterator->arg_index & 31) == 0))
230     {
231       /* completed current u32 bitmap */
232       if (iterator->bitmap_shifter & 1)
233       {
234         /* b31 was set, there is more */
235         /* move to next u32 bitmap */
236         iterator->bitmap_shifter = le32_to_cpu (*iterator->next_bitmap);
237         iterator->next_bitmap++;
238       }
239       else
240       {
241         /* no more bitmaps: end */
242         iterator->arg_index = sizeof (rt_sizes);
243       }
244     }
245     else
246     {                           /* just try the next bit */
247       iterator->bitmap_shifter >>= 1;
248     }
249
250     /* if we found a valid arg earlier, return it now */
251
252     if (hit)
253       return (iterator->this_arg_index);
254
255   }
256
257   /* we don't know how to handle any more args, we're done */
258
259   return (-1);
260 }