radiotap.c
Go to the documentation of this file.
00001 /*
00002  * Radiotap parser
00003  *
00004  * Copyright 2007               Andy Green <andy@warmcat.com>
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License version 2 as
00008  * published by the Free Software Foundation.
00009  *
00010  * Alternatively, this software may be distributed under the terms of BSD
00011  * license.
00012  *
00013  * See README and COPYING for more details.
00014  *
00015  *
00016  * Modified for userspace by Johannes Berg <johannes@sipsolutions.net>
00017  * I only modified some things on top to ease syncing should bugs be found.
00018  */
00019 
00020 #include "includes.h"
00021 
00022 #include "common.h"
00023 #include "radiotap_iter.h"
00024 
00025 #define le16_to_cpu             le_to_host16
00026 #define le32_to_cpu             le_to_host32
00027 #define __le32                  uint32_t
00028 #define ulong                   unsigned long
00029 #define unlikely(cond)          (cond)
00030 #define get_unaligned(p)                                        \
00031 ({                                                              \
00032         struct packed_dummy_struct {                            \
00033                 typeof(*(p)) __val;                             \
00034         } __attribute__((packed)) *__ptr = (void *) (p);        \
00035                                                                 \
00036         __ptr->__val;                                           \
00037 })
00038 
00039 /* function prototypes and related defs are in radiotap_iter.h */
00040 
00080 int ieee80211_radiotap_iterator_init(
00081     struct ieee80211_radiotap_iterator *iterator,
00082     struct ieee80211_radiotap_header *radiotap_header,
00083     int max_length)
00084 {
00085         /* Linux only supports version 0 radiotap format */
00086         if (radiotap_header->it_version)
00087                 return -EINVAL;
00088 
00089         /* sanity check for allowed length and radiotap length field */
00090         if (max_length < le16_to_cpu(get_unaligned(&radiotap_header->it_len)))
00091                 return -EINVAL;
00092 
00093         iterator->rtheader = radiotap_header;
00094         iterator->max_length = le16_to_cpu(get_unaligned(
00095                                                 &radiotap_header->it_len));
00096         iterator->arg_index = 0;
00097         iterator->bitmap_shifter = le32_to_cpu(get_unaligned(
00098                                                 &radiotap_header->it_present));
00099         iterator->arg = (u8 *)radiotap_header + sizeof(*radiotap_header);
00100         iterator->this_arg = NULL;
00101 
00102         /* find payload start allowing for extended bitmap(s) */
00103 
00104         if (unlikely(iterator->bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT))) {
00105                 while (le32_to_cpu(get_unaligned((__le32 *)iterator->arg)) &
00106                                    (1<<IEEE80211_RADIOTAP_EXT)) {
00107                         iterator->arg += sizeof(u32);
00108 
00109                         /*
00110                          * check for insanity where the present bitmaps
00111                          * keep claiming to extend up to or even beyond the
00112                          * stated radiotap header length
00113                          */
00114 
00115                         if (((ulong)iterator->arg - (ulong)iterator->rtheader)
00116                             > (ulong)iterator->max_length)
00117                                 return -EINVAL;
00118                 }
00119 
00120                 iterator->arg += sizeof(u32);
00121 
00122                 /*
00123                  * no need to check again for blowing past stated radiotap
00124                  * header length, because ieee80211_radiotap_iterator_next
00125                  * checks it before it is dereferenced
00126                  */
00127         }
00128 
00129         /* we are all initialized happily */
00130 
00131         return 0;
00132 }
00133 
00134 
00158 int ieee80211_radiotap_iterator_next(
00159     struct ieee80211_radiotap_iterator *iterator)
00160 {
00161 
00162         /*
00163          * small length lookup table for all radiotap types we heard of
00164          * starting from b0 in the bitmap, so we can walk the payload
00165          * area of the radiotap header
00166          *
00167          * There is a requirement to pad args, so that args
00168          * of a given length must begin at a boundary of that length
00169          * -- but note that compound args are allowed (eg, 2 x u16
00170          * for IEEE80211_RADIOTAP_CHANNEL) so total arg length is not
00171          * a reliable indicator of alignment requirement.
00172          *
00173          * upper nybble: content alignment for arg
00174          * lower nybble: content length for arg
00175          */
00176 
00177         static const u8 rt_sizes[] = {
00178                 [IEEE80211_RADIOTAP_TSFT] = 0x88,
00179                 [IEEE80211_RADIOTAP_FLAGS] = 0x11,
00180                 [IEEE80211_RADIOTAP_RATE] = 0x11,
00181                 [IEEE80211_RADIOTAP_CHANNEL] = 0x24,
00182                 [IEEE80211_RADIOTAP_FHSS] = 0x22,
00183                 [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = 0x11,
00184                 [IEEE80211_RADIOTAP_DBM_ANTNOISE] = 0x11,
00185                 [IEEE80211_RADIOTAP_LOCK_QUALITY] = 0x22,
00186                 [IEEE80211_RADIOTAP_TX_ATTENUATION] = 0x22,
00187                 [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = 0x22,
00188                 [IEEE80211_RADIOTAP_DBM_TX_POWER] = 0x11,
00189                 [IEEE80211_RADIOTAP_ANTENNA] = 0x11,
00190                 [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = 0x11,
00191                 [IEEE80211_RADIOTAP_DB_ANTNOISE] = 0x11,
00192                 [IEEE80211_RADIOTAP_RX_FLAGS] = 0x22,
00193                 [IEEE80211_RADIOTAP_TX_FLAGS] = 0x22,
00194                 [IEEE80211_RADIOTAP_RTS_RETRIES] = 0x11,
00195                 [IEEE80211_RADIOTAP_DATA_RETRIES] = 0x11,
00196                 /*
00197                  * add more here as they are defined in
00198                  * include/net/ieee80211_radiotap.h
00199                  */
00200         };
00201 
00202         /*
00203          * for every radiotap entry we can at
00204          * least skip (by knowing the length)...
00205          */
00206 
00207         while (iterator->arg_index < (int) sizeof(rt_sizes)) {
00208                 int hit = 0;
00209                 int pad;
00210 
00211                 if (!(iterator->bitmap_shifter & 1))
00212                         goto next_entry; /* arg not present */
00213 
00214                 /*
00215                  * arg is present, account for alignment padding
00216                  *  8-bit args can be at any alignment
00217                  * 16-bit args must start on 16-bit boundary
00218                  * 32-bit args must start on 32-bit boundary
00219                  * 64-bit args must start on 64-bit boundary
00220                  *
00221                  * note that total arg size can differ from alignment of
00222                  * elements inside arg, so we use upper nybble of length
00223                  * table to base alignment on
00224                  *
00225                  * also note: these alignments are ** relative to the
00226                  * start of the radiotap header **.  There is no guarantee
00227                  * that the radiotap header itself is aligned on any
00228                  * kind of boundary.
00229                  *
00230                  * the above is why get_unaligned() is used to dereference
00231                  * multibyte elements from the radiotap area
00232                  */
00233 
00234                 pad = (((ulong)iterator->arg) -
00235                         ((ulong)iterator->rtheader)) &
00236                         ((rt_sizes[iterator->arg_index] >> 4) - 1);
00237 
00238                 if (pad)
00239                         iterator->arg +=
00240                                 (rt_sizes[iterator->arg_index] >> 4) - pad;
00241 
00242                 /*
00243                  * this is what we will return to user, but we need to
00244                  * move on first so next call has something fresh to test
00245                  */
00246                 iterator->this_arg_index = iterator->arg_index;
00247                 iterator->this_arg = iterator->arg;
00248                 hit = 1;
00249 
00250                 /* internally move on the size of this arg */
00251                 iterator->arg += rt_sizes[iterator->arg_index] & 0x0f;
00252 
00253                 /*
00254                  * check for insanity where we are given a bitmap that
00255                  * claims to have more arg content than the length of the
00256                  * radiotap section.  We will normally end up equalling this
00257                  * max_length on the last arg, never exceeding it.
00258                  */
00259 
00260                 if (((ulong)iterator->arg - (ulong)iterator->rtheader) >
00261                     (ulong) iterator->max_length)
00262                         return -EINVAL;
00263 
00264         next_entry:
00265                 iterator->arg_index++;
00266                 if (unlikely((iterator->arg_index & 31) == 0)) {
00267                         /* completed current u32 bitmap */
00268                         if (iterator->bitmap_shifter & 1) {
00269                                 /* b31 was set, there is more */
00270                                 /* move to next u32 bitmap */
00271                                 iterator->bitmap_shifter = le32_to_cpu(
00272                                         get_unaligned(iterator->next_bitmap));
00273                                 iterator->next_bitmap++;
00274                         } else
00275                                 /* no more bitmaps: end */
00276                                 iterator->arg_index = sizeof(rt_sizes);
00277                 } else /* just try the next bit */
00278                         iterator->bitmap_shifter >>= 1;
00279 
00280                 /* if we found a valid arg earlier, return it now */
00281                 if (hit)
00282                         return 0;
00283         }
00284 
00285         /* we don't know how to handle any more args, we're done */
00286         return -ENOENT;
00287 }


wpa_supplicant
Author(s): Package maintained by Blaise Gassend
autogenerated on Thu Jan 2 2014 11:26:38