LCOV - code coverage report
Current view: top level - net/wireless - radiotap.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 110 0.0 %
Date: 2022-03-28 13:20:08 Functions: 0 2 0.0 %
Branches: 0 67 0.0 %

           Branch data     Line data    Source code
       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 <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                 :            : /* function prototypes and related defs are in include/net/cfg80211.h */
      24                 :            : 
      25                 :            : static 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                 :            :         [IEEE80211_RADIOTAP_VHT] = { .align = 2, .size = 12, },
      47                 :            :         /*
      48                 :            :          * add more here as they are defined in radiotap.h
      49                 :            :          */
      50                 :            : };
      51                 :            : 
      52                 :            : static const struct ieee80211_radiotap_namespace radiotap_ns = {
      53                 :            :         .n_bits = ARRAY_SIZE(rtap_namespace_sizes),
      54                 :            :         .align_size = rtap_namespace_sizes,
      55                 :            : };
      56                 :            : 
      57                 :            : /**
      58                 :            :  * ieee80211_radiotap_iterator_init - radiotap parser iterator initialization
      59                 :            :  * @iterator: radiotap_iterator to initialize
      60                 :            :  * @radiotap_header: radiotap header to parse
      61                 :            :  * @max_length: total length we can parse into (eg, whole packet length)
      62                 :            :  *
      63                 :            :  * Returns: 0 or a negative error code if there is a problem.
      64                 :            :  *
      65                 :            :  * This function initializes an opaque iterator struct which can then
      66                 :            :  * be passed to ieee80211_radiotap_iterator_next() to visit every radiotap
      67                 :            :  * argument which is present in the header.  It knows about extended
      68                 :            :  * present headers and handles them.
      69                 :            :  *
      70                 :            :  * How to use:
      71                 :            :  * call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator
      72                 :            :  * struct ieee80211_radiotap_iterator (no need to init the struct beforehand)
      73                 :            :  * checking for a good 0 return code.  Then loop calling
      74                 :            :  * __ieee80211_radiotap_iterator_next()... it returns either 0,
      75                 :            :  * -ENOENT if there are no more args to parse, or -EINVAL if there is a problem.
      76                 :            :  * The iterator's @this_arg member points to the start of the argument
      77                 :            :  * associated with the current argument index that is present, which can be
      78                 :            :  * found in the iterator's @this_arg_index member.  This arg index corresponds
      79                 :            :  * to the IEEE80211_RADIOTAP_... defines.
      80                 :            :  *
      81                 :            :  * Radiotap header length:
      82                 :            :  * You can find the CPU-endian total radiotap header length in
      83                 :            :  * iterator->max_length after executing ieee80211_radiotap_iterator_init()
      84                 :            :  * successfully.
      85                 :            :  *
      86                 :            :  * Alignment Gotcha:
      87                 :            :  * You must take care when dereferencing iterator.this_arg
      88                 :            :  * for multibyte types... the pointer is not aligned.  Use
      89                 :            :  * get_unaligned((type *)iterator.this_arg) to dereference
      90                 :            :  * iterator.this_arg for type "type" safely on all arches.
      91                 :            :  *
      92                 :            :  * Example code:
      93                 :            :  * See Documentation/networking/radiotap-headers.txt
      94                 :            :  */
      95                 :            : 
      96                 :          0 : int ieee80211_radiotap_iterator_init(
      97                 :            :         struct ieee80211_radiotap_iterator *iterator,
      98                 :            :         struct ieee80211_radiotap_header *radiotap_header,
      99                 :            :         int max_length, const struct ieee80211_radiotap_vendor_namespaces *vns)
     100                 :            : {
     101                 :            :         /* check the radiotap header can actually be present */
     102         [ #  # ]:          0 :         if (max_length < sizeof(struct ieee80211_radiotap_header))
     103                 :            :                 return -EINVAL;
     104                 :            : 
     105                 :            :         /* Linux only supports version 0 radiotap format */
     106         [ #  # ]:          0 :         if (radiotap_header->it_version)
     107                 :            :                 return -EINVAL;
     108                 :            : 
     109                 :            :         /* sanity check for allowed length and radiotap length field */
     110         [ #  # ]:          0 :         if (max_length < get_unaligned_le16(&radiotap_header->it_len))
     111                 :            :                 return -EINVAL;
     112                 :            : 
     113                 :          0 :         iterator->_rtheader = radiotap_header;
     114         [ #  # ]:          0 :         iterator->_max_length = get_unaligned_le16(&radiotap_header->it_len);
     115                 :          0 :         iterator->_arg_index = 0;
     116         [ #  # ]:          0 :         iterator->_bitmap_shifter = get_unaligned_le32(&radiotap_header->it_present);
     117                 :          0 :         iterator->_arg = (uint8_t *)radiotap_header + sizeof(*radiotap_header);
     118                 :          0 :         iterator->_reset_on_ext = 0;
     119                 :          0 :         iterator->_next_bitmap = &radiotap_header->it_present;
     120                 :          0 :         iterator->_next_bitmap++;
     121                 :          0 :         iterator->_vns = vns;
     122                 :          0 :         iterator->current_namespace = &radiotap_ns;
     123                 :          0 :         iterator->is_radiotap_ns = 1;
     124                 :            : 
     125                 :            :         /* find payload start allowing for extended bitmap(s) */
     126                 :            : 
     127         [ #  # ]:          0 :         if (iterator->_bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT)) {
     128                 :          0 :                 if ((unsigned long)iterator->_arg -
     129                 :          0 :                     (unsigned long)iterator->_rtheader + sizeof(uint32_t) >
     130         [ #  # ]:          0 :                     (unsigned long)iterator->_max_length)
     131                 :            :                         return -EINVAL;
     132         [ #  # ]:          0 :                 while (get_unaligned_le32(iterator->_arg) &
     133                 :            :                                         (1 << IEEE80211_RADIOTAP_EXT)) {
     134                 :          0 :                         iterator->_arg += sizeof(uint32_t);
     135                 :            : 
     136                 :            :                         /*
     137                 :            :                          * check for insanity where the present bitmaps
     138                 :            :                          * keep claiming to extend up to or even beyond the
     139                 :            :                          * stated radiotap header length
     140                 :            :                          */
     141                 :            : 
     142                 :          0 :                         if ((unsigned long)iterator->_arg -
     143         [ #  # ]:          0 :                             (unsigned long)iterator->_rtheader +
     144                 :            :                             sizeof(uint32_t) >
     145                 :            :                             (unsigned long)iterator->_max_length)
     146                 :            :                                 return -EINVAL;
     147                 :            :                 }
     148                 :            : 
     149                 :          0 :                 iterator->_arg += sizeof(uint32_t);
     150                 :            : 
     151                 :            :                 /*
     152                 :            :                  * no need to check again for blowing past stated radiotap
     153                 :            :                  * header length, because ieee80211_radiotap_iterator_next
     154                 :            :                  * checks it before it is dereferenced
     155                 :            :                  */
     156                 :            :         }
     157                 :            : 
     158                 :          0 :         iterator->this_arg = iterator->_arg;
     159                 :            : 
     160                 :            :         /* we are all initialized happily */
     161                 :            : 
     162                 :          0 :         return 0;
     163                 :            : }
     164                 :            : EXPORT_SYMBOL(ieee80211_radiotap_iterator_init);
     165                 :            : 
     166                 :          0 : static void find_ns(struct ieee80211_radiotap_iterator *iterator,
     167                 :            :                     uint32_t oui, uint8_t subns)
     168                 :            : {
     169                 :          0 :         int i;
     170                 :            : 
     171                 :          0 :         iterator->current_namespace = NULL;
     172                 :            : 
     173                 :          0 :         if (!iterator->_vns)
     174                 :            :                 return;
     175                 :            : 
     176         [ #  # ]:          0 :         for (i = 0; i < iterator->_vns->n_ns; i++) {
     177         [ #  # ]:          0 :                 if (iterator->_vns->ns[i].oui != oui)
     178                 :          0 :                         continue;
     179         [ #  # ]:          0 :                 if (iterator->_vns->ns[i].subns != subns)
     180                 :          0 :                         continue;
     181                 :            : 
     182                 :          0 :                 iterator->current_namespace = &iterator->_vns->ns[i];
     183                 :          0 :                 break;
     184                 :            :         }
     185                 :            : }
     186                 :            : 
     187                 :            : 
     188                 :            : 
     189                 :            : /**
     190                 :            :  * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg
     191                 :            :  * @iterator: radiotap_iterator to move to next arg (if any)
     192                 :            :  *
     193                 :            :  * Returns: 0 if there is an argument to handle,
     194                 :            :  * -ENOENT if there are no more args or -EINVAL
     195                 :            :  * if there is something else wrong.
     196                 :            :  *
     197                 :            :  * This function provides the next radiotap arg index (IEEE80211_RADIOTAP_*)
     198                 :            :  * in @this_arg_index and sets @this_arg to point to the
     199                 :            :  * payload for the field.  It takes care of alignment handling and extended
     200                 :            :  * present fields.  @this_arg can be changed by the caller (eg,
     201                 :            :  * incremented to move inside a compound argument like
     202                 :            :  * IEEE80211_RADIOTAP_CHANNEL).  The args pointed to are in
     203                 :            :  * little-endian format whatever the endianess of your CPU.
     204                 :            :  *
     205                 :            :  * Alignment Gotcha:
     206                 :            :  * You must take care when dereferencing iterator.this_arg
     207                 :            :  * for multibyte types... the pointer is not aligned.  Use
     208                 :            :  * get_unaligned((type *)iterator.this_arg) to dereference
     209                 :            :  * iterator.this_arg for type "type" safely on all arches.
     210                 :            :  */
     211                 :            : 
     212                 :          0 : int ieee80211_radiotap_iterator_next(
     213                 :            :         struct ieee80211_radiotap_iterator *iterator)
     214                 :            : {
     215                 :          0 :         while (1) {
     216                 :          0 :                 int hit = 0;
     217                 :          0 :                 int pad, align, size, subns;
     218                 :          0 :                 uint32_t oui;
     219                 :            : 
     220                 :            :                 /* if no more EXT bits, that's it */
     221         [ #  # ]:          0 :                 if ((iterator->_arg_index % 32) == IEEE80211_RADIOTAP_EXT &&
     222         [ #  # ]:          0 :                     !(iterator->_bitmap_shifter & 1))
     223                 :            :                         return -ENOENT;
     224                 :            : 
     225         [ #  # ]:          0 :                 if (!(iterator->_bitmap_shifter & 1))
     226                 :          0 :                         goto next_entry; /* arg not present */
     227                 :            : 
     228                 :            :                 /* get alignment/size of data */
     229      [ #  #  # ]:          0 :                 switch (iterator->_arg_index % 32) {
     230                 :            :                 case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE:
     231                 :            :                 case IEEE80211_RADIOTAP_EXT:
     232                 :            :                         align = 1;
     233                 :            :                         size = 0;
     234                 :            :                         break;
     235                 :          0 :                 case IEEE80211_RADIOTAP_VENDOR_NAMESPACE:
     236                 :          0 :                         align = 2;
     237                 :          0 :                         size = 6;
     238                 :          0 :                         break;
     239                 :          0 :                 default:
     240         [ #  # ]:          0 :                         if (!iterator->current_namespace ||
     241         [ #  # ]:          0 :                             iterator->_arg_index >= iterator->current_namespace->n_bits) {
     242         [ #  # ]:          0 :                                 if (iterator->current_namespace == &radiotap_ns)
     243                 :            :                                         return -ENOENT;
     244                 :            :                                 align = 0;
     245                 :            :                         } else {
     246                 :          0 :                                 align = iterator->current_namespace->align_size[iterator->_arg_index].align;
     247                 :          0 :                                 size = iterator->current_namespace->align_size[iterator->_arg_index].size;
     248                 :            :                         }
     249         [ #  # ]:          0 :                         if (!align) {
     250                 :            :                                 /* skip all subsequent data */
     251                 :          0 :                                 iterator->_arg = iterator->_next_ns_data;
     252                 :            :                                 /* give up on this namespace */
     253                 :          0 :                                 iterator->current_namespace = NULL;
     254                 :          0 :                                 goto next_entry;
     255                 :            :                         }
     256                 :            :                         break;
     257                 :            :                 }
     258                 :            : 
     259                 :            :                 /*
     260                 :            :                  * arg is present, account for alignment padding
     261                 :            :                  *
     262                 :            :                  * Note that these alignments are relative to the start
     263                 :            :                  * of the radiotap header.  There is no guarantee
     264                 :            :                  * that the radiotap header itself is aligned on any
     265                 :            :                  * kind of boundary.
     266                 :            :                  *
     267                 :            :                  * The above is why get_unaligned() is used to dereference
     268                 :            :                  * multibyte elements from the radiotap area.
     269                 :            :                  */
     270                 :            : 
     271                 :          0 :                 pad = ((unsigned long)iterator->_arg -
     272                 :          0 :                        (unsigned long)iterator->_rtheader) & (align - 1);
     273                 :            : 
     274         [ #  # ]:          0 :                 if (pad)
     275                 :          0 :                         iterator->_arg += align - pad;
     276                 :            : 
     277         [ #  # ]:          0 :                 if (iterator->_arg_index % 32 == IEEE80211_RADIOTAP_VENDOR_NAMESPACE) {
     278                 :          0 :                         int vnslen;
     279                 :            : 
     280                 :          0 :                         if ((unsigned long)iterator->_arg + size -
     281                 :            :                             (unsigned long)iterator->_rtheader >
     282         [ #  # ]:          0 :                             (unsigned long)iterator->_max_length)
     283                 :            :                                 return -EINVAL;
     284                 :            : 
     285                 :          0 :                         oui = (*iterator->_arg << 16) |
     286                 :          0 :                                 (*(iterator->_arg + 1) << 8) |
     287                 :          0 :                                 *(iterator->_arg + 2);
     288                 :          0 :                         subns = *(iterator->_arg + 3);
     289                 :            : 
     290         [ #  # ]:          0 :                         find_ns(iterator, oui, subns);
     291                 :            : 
     292         [ #  # ]:          0 :                         vnslen = get_unaligned_le16(iterator->_arg + 4);
     293                 :          0 :                         iterator->_next_ns_data = iterator->_arg + size + vnslen;
     294         [ #  # ]:          0 :                         if (!iterator->current_namespace)
     295                 :          0 :                                 size += vnslen;
     296                 :            :                 }
     297                 :            : 
     298                 :            :                 /*
     299                 :            :                  * this is what we will return to user, but we need to
     300                 :            :                  * move on first so next call has something fresh to test
     301                 :            :                  */
     302                 :          0 :                 iterator->this_arg_index = iterator->_arg_index;
     303                 :          0 :                 iterator->this_arg = iterator->_arg;
     304                 :          0 :                 iterator->this_arg_size = size;
     305                 :            : 
     306                 :            :                 /* internally move on the size of this arg */
     307                 :          0 :                 iterator->_arg += size;
     308                 :            : 
     309                 :            :                 /*
     310                 :            :                  * check for insanity where we are given a bitmap that
     311                 :            :                  * claims to have more arg content than the length of the
     312                 :            :                  * radiotap section.  We will normally end up equalling this
     313                 :            :                  * max_length on the last arg, never exceeding it.
     314                 :            :                  */
     315                 :            : 
     316                 :          0 :                 if ((unsigned long)iterator->_arg -
     317                 :            :                     (unsigned long)iterator->_rtheader >
     318         [ #  # ]:          0 :                     (unsigned long)iterator->_max_length)
     319                 :            :                         return -EINVAL;
     320                 :            : 
     321                 :            :                 /* these special ones are valid in each bitmap word */
     322   [ #  #  #  # ]:          0 :                 switch (iterator->_arg_index % 32) {
     323                 :          0 :                 case IEEE80211_RADIOTAP_VENDOR_NAMESPACE:
     324                 :          0 :                         iterator->_reset_on_ext = 1;
     325                 :            : 
     326                 :          0 :                         iterator->is_radiotap_ns = 0;
     327                 :            :                         /*
     328                 :            :                          * If parser didn't register this vendor
     329                 :            :                          * namespace with us, allow it to show it
     330                 :            :                          * as 'raw. Do do that, set argument index
     331                 :            :                          * to vendor namespace.
     332                 :            :                          */
     333                 :          0 :                         iterator->this_arg_index =
     334                 :            :                                 IEEE80211_RADIOTAP_VENDOR_NAMESPACE;
     335         [ #  # ]:          0 :                         if (!iterator->current_namespace)
     336                 :          0 :                                 hit = 1;
     337                 :          0 :                         goto next_entry;
     338                 :          0 :                 case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE:
     339                 :          0 :                         iterator->_reset_on_ext = 1;
     340                 :          0 :                         iterator->current_namespace = &radiotap_ns;
     341                 :          0 :                         iterator->is_radiotap_ns = 1;
     342                 :          0 :                         goto next_entry;
     343                 :          0 :                 case IEEE80211_RADIOTAP_EXT:
     344                 :            :                         /*
     345                 :            :                          * bit 31 was set, there is more
     346                 :            :                          * -- move to next u32 bitmap
     347                 :            :                          */
     348                 :          0 :                         iterator->_bitmap_shifter =
     349         [ #  # ]:          0 :                                 get_unaligned_le32(iterator->_next_bitmap);
     350                 :          0 :                         iterator->_next_bitmap++;
     351         [ #  # ]:          0 :                         if (iterator->_reset_on_ext)
     352                 :          0 :                                 iterator->_arg_index = 0;
     353                 :            :                         else
     354                 :          0 :                                 iterator->_arg_index++;
     355                 :          0 :                         iterator->_reset_on_ext = 0;
     356                 :          0 :                         break;
     357                 :            :                 default:
     358                 :            :                         /* we've got a hit! */
     359                 :            :                         hit = 1;
     360                 :          0 :  next_entry:
     361                 :          0 :                         iterator->_bitmap_shifter >>= 1;
     362                 :          0 :                         iterator->_arg_index++;
     363                 :            :                 }
     364                 :            : 
     365                 :            :                 /* if we found a valid arg earlier, return it now */
     366         [ #  # ]:          0 :                 if (hit)
     367                 :            :                         return 0;
     368                 :            :         }
     369                 :            : }
     370                 :            : EXPORT_SYMBOL(ieee80211_radiotap_iterator_next);

Generated by: LCOV version 1.14