Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Radiotap parser
0003  *
0004  * Copyright 2007       Andy Green <andy@warmcat.com>
0005  * Copyright 2009       Johannes Berg <johannes@sipsolutions.net>
0006  *
0007  * This program is free software; you can redistribute it and/or modify
0008  * it under the terms of the GNU General Public License version 2 as
0009  * published by the Free Software Foundation.
0010  *
0011  * Alternatively, this software may be distributed under the terms of BSD
0012  * license.
0013  *
0014  * See COPYING for more details.
0015  */
0016 
0017 #include <linux/kernel.h>
0018 #include <linux/export.h>
0019 #include <net/cfg80211.h>
0020 #include <net/ieee80211_radiotap.h>
0021 #include <asm/unaligned.h>
0022 
0023 /* function prototypes and related defs are in include/net/cfg80211.h */
0024 
0025 static const struct radiotap_align_size rtap_namespace_sizes[] = {
0026     [IEEE80211_RADIOTAP_TSFT] = { .align = 8, .size = 8, },
0027     [IEEE80211_RADIOTAP_FLAGS] = { .align = 1, .size = 1, },
0028     [IEEE80211_RADIOTAP_RATE] = { .align = 1, .size = 1, },
0029     [IEEE80211_RADIOTAP_CHANNEL] = { .align = 2, .size = 4, },
0030     [IEEE80211_RADIOTAP_FHSS] = { .align = 2, .size = 2, },
0031     [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = { .align = 1, .size = 1, },
0032     [IEEE80211_RADIOTAP_DBM_ANTNOISE] = { .align = 1, .size = 1, },
0033     [IEEE80211_RADIOTAP_LOCK_QUALITY] = { .align = 2, .size = 2, },
0034     [IEEE80211_RADIOTAP_TX_ATTENUATION] = { .align = 2, .size = 2, },
0035     [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = { .align = 2, .size = 2, },
0036     [IEEE80211_RADIOTAP_DBM_TX_POWER] = { .align = 1, .size = 1, },
0037     [IEEE80211_RADIOTAP_ANTENNA] = { .align = 1, .size = 1, },
0038     [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = { .align = 1, .size = 1, },
0039     [IEEE80211_RADIOTAP_DB_ANTNOISE] = { .align = 1, .size = 1, },
0040     [IEEE80211_RADIOTAP_RX_FLAGS] = { .align = 2, .size = 2, },
0041     [IEEE80211_RADIOTAP_TX_FLAGS] = { .align = 2, .size = 2, },
0042     [IEEE80211_RADIOTAP_RTS_RETRIES] = { .align = 1, .size = 1, },
0043     [IEEE80211_RADIOTAP_DATA_RETRIES] = { .align = 1, .size = 1, },
0044     [IEEE80211_RADIOTAP_MCS] = { .align = 1, .size = 3, },
0045     [IEEE80211_RADIOTAP_AMPDU_STATUS] = { .align = 4, .size = 8, },
0046     [IEEE80211_RADIOTAP_VHT] = { .align = 2, .size = 12, },
0047     /*
0048      * add more here as they are defined in radiotap.h
0049      */
0050 };
0051 
0052 static const struct ieee80211_radiotap_namespace radiotap_ns = {
0053     .n_bits = ARRAY_SIZE(rtap_namespace_sizes),
0054     .align_size = rtap_namespace_sizes,
0055 };
0056 
0057 /**
0058  * ieee80211_radiotap_iterator_init - radiotap parser iterator initialization
0059  * @iterator: radiotap_iterator to initialize
0060  * @radiotap_header: radiotap header to parse
0061  * @max_length: total length we can parse into (eg, whole packet length)
0062  * @vns: vendor namespaces to parse
0063  *
0064  * Returns: 0 or a negative error code if there is a problem.
0065  *
0066  * This function initializes an opaque iterator struct which can then
0067  * be passed to ieee80211_radiotap_iterator_next() to visit every radiotap
0068  * argument which is present in the header.  It knows about extended
0069  * present headers and handles them.
0070  *
0071  * How to use:
0072  * call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator
0073  * struct ieee80211_radiotap_iterator (no need to init the struct beforehand)
0074  * checking for a good 0 return code.  Then loop calling
0075  * __ieee80211_radiotap_iterator_next()... it returns either 0,
0076  * -ENOENT if there are no more args to parse, or -EINVAL if there is a problem.
0077  * The iterator's @this_arg member points to the start of the argument
0078  * associated with the current argument index that is present, which can be
0079  * found in the iterator's @this_arg_index member.  This arg index corresponds
0080  * to the IEEE80211_RADIOTAP_... defines.
0081  *
0082  * Radiotap header length:
0083  * You can find the CPU-endian total radiotap header length in
0084  * iterator->max_length after executing ieee80211_radiotap_iterator_init()
0085  * successfully.
0086  *
0087  * Alignment Gotcha:
0088  * You must take care when dereferencing iterator.this_arg
0089  * for multibyte types... the pointer is not aligned.  Use
0090  * get_unaligned((type *)iterator.this_arg) to dereference
0091  * iterator.this_arg for type "type" safely on all arches.
0092  *
0093  * Example code:
0094  * See Documentation/networking/radiotap-headers.rst
0095  */
0096 
0097 int ieee80211_radiotap_iterator_init(
0098     struct ieee80211_radiotap_iterator *iterator,
0099     struct ieee80211_radiotap_header *radiotap_header,
0100     int max_length, const struct ieee80211_radiotap_vendor_namespaces *vns)
0101 {
0102     /* check the radiotap header can actually be present */
0103     if (max_length < sizeof(struct ieee80211_radiotap_header))
0104         return -EINVAL;
0105 
0106     /* Linux only supports version 0 radiotap format */
0107     if (radiotap_header->it_version)
0108         return -EINVAL;
0109 
0110     /* sanity check for allowed length and radiotap length field */
0111     if (max_length < get_unaligned_le16(&radiotap_header->it_len))
0112         return -EINVAL;
0113 
0114     iterator->_rtheader = radiotap_header;
0115     iterator->_max_length = get_unaligned_le16(&radiotap_header->it_len);
0116     iterator->_arg_index = 0;
0117     iterator->_bitmap_shifter = get_unaligned_le32(&radiotap_header->it_present);
0118     iterator->_arg = (uint8_t *)radiotap_header->it_optional;
0119     iterator->_reset_on_ext = 0;
0120     iterator->_next_bitmap = radiotap_header->it_optional;
0121     iterator->_vns = vns;
0122     iterator->current_namespace = &radiotap_ns;
0123     iterator->is_radiotap_ns = 1;
0124 
0125     /* find payload start allowing for extended bitmap(s) */
0126 
0127     if (iterator->_bitmap_shifter & (BIT(IEEE80211_RADIOTAP_EXT))) {
0128         if ((unsigned long)iterator->_arg -
0129             (unsigned long)iterator->_rtheader + sizeof(uint32_t) >
0130             (unsigned long)iterator->_max_length)
0131             return -EINVAL;
0132         while (get_unaligned_le32(iterator->_arg) &
0133                     (BIT(IEEE80211_RADIOTAP_EXT))) {
0134             iterator->_arg += sizeof(uint32_t);
0135 
0136             /*
0137              * check for insanity where the present bitmaps
0138              * keep claiming to extend up to or even beyond the
0139              * stated radiotap header length
0140              */
0141 
0142             if ((unsigned long)iterator->_arg -
0143                 (unsigned long)iterator->_rtheader +
0144                 sizeof(uint32_t) >
0145                 (unsigned long)iterator->_max_length)
0146                 return -EINVAL;
0147         }
0148 
0149         iterator->_arg += sizeof(uint32_t);
0150 
0151         /*
0152          * no need to check again for blowing past stated radiotap
0153          * header length, because ieee80211_radiotap_iterator_next
0154          * checks it before it is dereferenced
0155          */
0156     }
0157 
0158     iterator->this_arg = iterator->_arg;
0159 
0160     /* we are all initialized happily */
0161 
0162     return 0;
0163 }
0164 EXPORT_SYMBOL(ieee80211_radiotap_iterator_init);
0165 
0166 static void find_ns(struct ieee80211_radiotap_iterator *iterator,
0167             uint32_t oui, uint8_t subns)
0168 {
0169     int i;
0170 
0171     iterator->current_namespace = NULL;
0172 
0173     if (!iterator->_vns)
0174         return;
0175 
0176     for (i = 0; i < iterator->_vns->n_ns; i++) {
0177         if (iterator->_vns->ns[i].oui != oui)
0178             continue;
0179         if (iterator->_vns->ns[i].subns != subns)
0180             continue;
0181 
0182         iterator->current_namespace = &iterator->_vns->ns[i];
0183         break;
0184     }
0185 }
0186 
0187 
0188 
0189 /**
0190  * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg
0191  * @iterator: radiotap_iterator to move to next arg (if any)
0192  *
0193  * Returns: 0 if there is an argument to handle,
0194  * -ENOENT if there are no more args or -EINVAL
0195  * if there is something else wrong.
0196  *
0197  * This function provides the next radiotap arg index (IEEE80211_RADIOTAP_*)
0198  * in @this_arg_index and sets @this_arg to point to the
0199  * payload for the field.  It takes care of alignment handling and extended
0200  * present fields.  @this_arg can be changed by the caller (eg,
0201  * incremented to move inside a compound argument like
0202  * IEEE80211_RADIOTAP_CHANNEL).  The args pointed to are in
0203  * little-endian format whatever the endianess of your CPU.
0204  *
0205  * Alignment Gotcha:
0206  * You must take care when dereferencing iterator.this_arg
0207  * for multibyte types... the pointer is not aligned.  Use
0208  * get_unaligned((type *)iterator.this_arg) to dereference
0209  * iterator.this_arg for type "type" safely on all arches.
0210  */
0211 
0212 int ieee80211_radiotap_iterator_next(
0213     struct ieee80211_radiotap_iterator *iterator)
0214 {
0215     while (1) {
0216         int hit = 0;
0217         int pad, align, size, subns;
0218         uint32_t oui;
0219 
0220         /* if no more EXT bits, that's it */
0221         if ((iterator->_arg_index % 32) == IEEE80211_RADIOTAP_EXT &&
0222             !(iterator->_bitmap_shifter & 1))
0223             return -ENOENT;
0224 
0225         if (!(iterator->_bitmap_shifter & 1))
0226             goto next_entry; /* arg not present */
0227 
0228         /* get alignment/size of data */
0229         switch (iterator->_arg_index % 32) {
0230         case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE:
0231         case IEEE80211_RADIOTAP_EXT:
0232             align = 1;
0233             size = 0;
0234             break;
0235         case IEEE80211_RADIOTAP_VENDOR_NAMESPACE:
0236             align = 2;
0237             size = 6;
0238             break;
0239         default:
0240             if (!iterator->current_namespace ||
0241                 iterator->_arg_index >= iterator->current_namespace->n_bits) {
0242                 if (iterator->current_namespace == &radiotap_ns)
0243                     return -ENOENT;
0244                 align = 0;
0245             } else {
0246                 align = iterator->current_namespace->align_size[iterator->_arg_index].align;
0247                 size = iterator->current_namespace->align_size[iterator->_arg_index].size;
0248             }
0249             if (!align) {
0250                 /* skip all subsequent data */
0251                 iterator->_arg = iterator->_next_ns_data;
0252                 /* give up on this namespace */
0253                 iterator->current_namespace = NULL;
0254                 goto next_entry;
0255             }
0256             break;
0257         }
0258 
0259         /*
0260          * arg is present, account for alignment padding
0261          *
0262          * Note that these alignments are relative to the start
0263          * of the radiotap header.  There is no guarantee
0264          * that the radiotap header itself is aligned on any
0265          * kind of boundary.
0266          *
0267          * The above is why get_unaligned() is used to dereference
0268          * multibyte elements from the radiotap area.
0269          */
0270 
0271         pad = ((unsigned long)iterator->_arg -
0272                (unsigned long)iterator->_rtheader) & (align - 1);
0273 
0274         if (pad)
0275             iterator->_arg += align - pad;
0276 
0277         if (iterator->_arg_index % 32 == IEEE80211_RADIOTAP_VENDOR_NAMESPACE) {
0278             int vnslen;
0279 
0280             if ((unsigned long)iterator->_arg + size -
0281                 (unsigned long)iterator->_rtheader >
0282                 (unsigned long)iterator->_max_length)
0283                 return -EINVAL;
0284 
0285             oui = (*iterator->_arg << 16) |
0286                 (*(iterator->_arg + 1) << 8) |
0287                 *(iterator->_arg + 2);
0288             subns = *(iterator->_arg + 3);
0289 
0290             find_ns(iterator, oui, subns);
0291 
0292             vnslen = get_unaligned_le16(iterator->_arg + 4);
0293             iterator->_next_ns_data = iterator->_arg + size + vnslen;
0294             if (!iterator->current_namespace)
0295                 size += vnslen;
0296         }
0297 
0298         /*
0299          * this is what we will return to user, but we need to
0300          * move on first so next call has something fresh to test
0301          */
0302         iterator->this_arg_index = iterator->_arg_index;
0303         iterator->this_arg = iterator->_arg;
0304         iterator->this_arg_size = size;
0305 
0306         /* internally move on the size of this arg */
0307         iterator->_arg += size;
0308 
0309         /*
0310          * check for insanity where we are given a bitmap that
0311          * claims to have more arg content than the length of the
0312          * radiotap section.  We will normally end up equalling this
0313          * max_length on the last arg, never exceeding it.
0314          */
0315 
0316         if ((unsigned long)iterator->_arg -
0317             (unsigned long)iterator->_rtheader >
0318             (unsigned long)iterator->_max_length)
0319             return -EINVAL;
0320 
0321         /* these special ones are valid in each bitmap word */
0322         switch (iterator->_arg_index % 32) {
0323         case IEEE80211_RADIOTAP_VENDOR_NAMESPACE:
0324             iterator->_reset_on_ext = 1;
0325 
0326             iterator->is_radiotap_ns = 0;
0327             /*
0328              * If parser didn't register this vendor
0329              * namespace with us, allow it to show it
0330              * as 'raw. Do do that, set argument index
0331              * to vendor namespace.
0332              */
0333             iterator->this_arg_index =
0334                 IEEE80211_RADIOTAP_VENDOR_NAMESPACE;
0335             if (!iterator->current_namespace)
0336                 hit = 1;
0337             goto next_entry;
0338         case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE:
0339             iterator->_reset_on_ext = 1;
0340             iterator->current_namespace = &radiotap_ns;
0341             iterator->is_radiotap_ns = 1;
0342             goto next_entry;
0343         case IEEE80211_RADIOTAP_EXT:
0344             /*
0345              * bit 31 was set, there is more
0346              * -- move to next u32 bitmap
0347              */
0348             iterator->_bitmap_shifter =
0349                 get_unaligned_le32(iterator->_next_bitmap);
0350             iterator->_next_bitmap++;
0351             if (iterator->_reset_on_ext)
0352                 iterator->_arg_index = 0;
0353             else
0354                 iterator->_arg_index++;
0355             iterator->_reset_on_ext = 0;
0356             break;
0357         default:
0358             /* we've got a hit! */
0359             hit = 1;
0360  next_entry:
0361             iterator->_bitmap_shifter >>= 1;
0362             iterator->_arg_index++;
0363         }
0364 
0365         /* if we found a valid arg earlier, return it now */
0366         if (hit)
0367             return 0;
0368     }
0369 }
0370 EXPORT_SYMBOL(ieee80211_radiotap_iterator_next);