18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Radiotap parser 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright 2007 Andy Green <andy@warmcat.com> 58c2ecf20Sopenharmony_ci * Copyright 2009 Johannes Berg <johannes@sipsolutions.net> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 88c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License version 2 as 98c2ecf20Sopenharmony_ci * published by the Free Software Foundation. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Alternatively, this software may be distributed under the terms of BSD 128c2ecf20Sopenharmony_ci * license. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * See COPYING for more details. 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <linux/kernel.h> 188c2ecf20Sopenharmony_ci#include <linux/export.h> 198c2ecf20Sopenharmony_ci#include <net/cfg80211.h> 208c2ecf20Sopenharmony_ci#include <net/ieee80211_radiotap.h> 218c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/* function prototypes and related defs are in include/net/cfg80211.h */ 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic const struct radiotap_align_size rtap_namespace_sizes[] = { 268c2ecf20Sopenharmony_ci [IEEE80211_RADIOTAP_TSFT] = { .align = 8, .size = 8, }, 278c2ecf20Sopenharmony_ci [IEEE80211_RADIOTAP_FLAGS] = { .align = 1, .size = 1, }, 288c2ecf20Sopenharmony_ci [IEEE80211_RADIOTAP_RATE] = { .align = 1, .size = 1, }, 298c2ecf20Sopenharmony_ci [IEEE80211_RADIOTAP_CHANNEL] = { .align = 2, .size = 4, }, 308c2ecf20Sopenharmony_ci [IEEE80211_RADIOTAP_FHSS] = { .align = 2, .size = 2, }, 318c2ecf20Sopenharmony_ci [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = { .align = 1, .size = 1, }, 328c2ecf20Sopenharmony_ci [IEEE80211_RADIOTAP_DBM_ANTNOISE] = { .align = 1, .size = 1, }, 338c2ecf20Sopenharmony_ci [IEEE80211_RADIOTAP_LOCK_QUALITY] = { .align = 2, .size = 2, }, 348c2ecf20Sopenharmony_ci [IEEE80211_RADIOTAP_TX_ATTENUATION] = { .align = 2, .size = 2, }, 358c2ecf20Sopenharmony_ci [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = { .align = 2, .size = 2, }, 368c2ecf20Sopenharmony_ci [IEEE80211_RADIOTAP_DBM_TX_POWER] = { .align = 1, .size = 1, }, 378c2ecf20Sopenharmony_ci [IEEE80211_RADIOTAP_ANTENNA] = { .align = 1, .size = 1, }, 388c2ecf20Sopenharmony_ci [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = { .align = 1, .size = 1, }, 398c2ecf20Sopenharmony_ci [IEEE80211_RADIOTAP_DB_ANTNOISE] = { .align = 1, .size = 1, }, 408c2ecf20Sopenharmony_ci [IEEE80211_RADIOTAP_RX_FLAGS] = { .align = 2, .size = 2, }, 418c2ecf20Sopenharmony_ci [IEEE80211_RADIOTAP_TX_FLAGS] = { .align = 2, .size = 2, }, 428c2ecf20Sopenharmony_ci [IEEE80211_RADIOTAP_RTS_RETRIES] = { .align = 1, .size = 1, }, 438c2ecf20Sopenharmony_ci [IEEE80211_RADIOTAP_DATA_RETRIES] = { .align = 1, .size = 1, }, 448c2ecf20Sopenharmony_ci [IEEE80211_RADIOTAP_MCS] = { .align = 1, .size = 3, }, 458c2ecf20Sopenharmony_ci [IEEE80211_RADIOTAP_AMPDU_STATUS] = { .align = 4, .size = 8, }, 468c2ecf20Sopenharmony_ci [IEEE80211_RADIOTAP_VHT] = { .align = 2, .size = 12, }, 478c2ecf20Sopenharmony_ci /* 488c2ecf20Sopenharmony_ci * add more here as they are defined in radiotap.h 498c2ecf20Sopenharmony_ci */ 508c2ecf20Sopenharmony_ci}; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic const struct ieee80211_radiotap_namespace radiotap_ns = { 538c2ecf20Sopenharmony_ci .n_bits = ARRAY_SIZE(rtap_namespace_sizes), 548c2ecf20Sopenharmony_ci .align_size = rtap_namespace_sizes, 558c2ecf20Sopenharmony_ci}; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci/** 588c2ecf20Sopenharmony_ci * ieee80211_radiotap_iterator_init - radiotap parser iterator initialization 598c2ecf20Sopenharmony_ci * @iterator: radiotap_iterator to initialize 608c2ecf20Sopenharmony_ci * @radiotap_header: radiotap header to parse 618c2ecf20Sopenharmony_ci * @max_length: total length we can parse into (eg, whole packet length) 628c2ecf20Sopenharmony_ci * @vns: vendor namespaces to parse 638c2ecf20Sopenharmony_ci * 648c2ecf20Sopenharmony_ci * Returns: 0 or a negative error code if there is a problem. 658c2ecf20Sopenharmony_ci * 668c2ecf20Sopenharmony_ci * This function initializes an opaque iterator struct which can then 678c2ecf20Sopenharmony_ci * be passed to ieee80211_radiotap_iterator_next() to visit every radiotap 688c2ecf20Sopenharmony_ci * argument which is present in the header. It knows about extended 698c2ecf20Sopenharmony_ci * present headers and handles them. 708c2ecf20Sopenharmony_ci * 718c2ecf20Sopenharmony_ci * How to use: 728c2ecf20Sopenharmony_ci * call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator 738c2ecf20Sopenharmony_ci * struct ieee80211_radiotap_iterator (no need to init the struct beforehand) 748c2ecf20Sopenharmony_ci * checking for a good 0 return code. Then loop calling 758c2ecf20Sopenharmony_ci * __ieee80211_radiotap_iterator_next()... it returns either 0, 768c2ecf20Sopenharmony_ci * -ENOENT if there are no more args to parse, or -EINVAL if there is a problem. 778c2ecf20Sopenharmony_ci * The iterator's @this_arg member points to the start of the argument 788c2ecf20Sopenharmony_ci * associated with the current argument index that is present, which can be 798c2ecf20Sopenharmony_ci * found in the iterator's @this_arg_index member. This arg index corresponds 808c2ecf20Sopenharmony_ci * to the IEEE80211_RADIOTAP_... defines. 818c2ecf20Sopenharmony_ci * 828c2ecf20Sopenharmony_ci * Radiotap header length: 838c2ecf20Sopenharmony_ci * You can find the CPU-endian total radiotap header length in 848c2ecf20Sopenharmony_ci * iterator->max_length after executing ieee80211_radiotap_iterator_init() 858c2ecf20Sopenharmony_ci * successfully. 868c2ecf20Sopenharmony_ci * 878c2ecf20Sopenharmony_ci * Alignment Gotcha: 888c2ecf20Sopenharmony_ci * You must take care when dereferencing iterator.this_arg 898c2ecf20Sopenharmony_ci * for multibyte types... the pointer is not aligned. Use 908c2ecf20Sopenharmony_ci * get_unaligned((type *)iterator.this_arg) to dereference 918c2ecf20Sopenharmony_ci * iterator.this_arg for type "type" safely on all arches. 928c2ecf20Sopenharmony_ci * 938c2ecf20Sopenharmony_ci * Example code: 948c2ecf20Sopenharmony_ci * See Documentation/networking/radiotap-headers.rst 958c2ecf20Sopenharmony_ci */ 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ciint ieee80211_radiotap_iterator_init( 988c2ecf20Sopenharmony_ci struct ieee80211_radiotap_iterator *iterator, 998c2ecf20Sopenharmony_ci struct ieee80211_radiotap_header *radiotap_header, 1008c2ecf20Sopenharmony_ci int max_length, const struct ieee80211_radiotap_vendor_namespaces *vns) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci /* check the radiotap header can actually be present */ 1038c2ecf20Sopenharmony_ci if (max_length < sizeof(struct ieee80211_radiotap_header)) 1048c2ecf20Sopenharmony_ci return -EINVAL; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci /* Linux only supports version 0 radiotap format */ 1078c2ecf20Sopenharmony_ci if (radiotap_header->it_version) 1088c2ecf20Sopenharmony_ci return -EINVAL; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci /* sanity check for allowed length and radiotap length field */ 1118c2ecf20Sopenharmony_ci if (max_length < get_unaligned_le16(&radiotap_header->it_len)) 1128c2ecf20Sopenharmony_ci return -EINVAL; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci iterator->_rtheader = radiotap_header; 1158c2ecf20Sopenharmony_ci iterator->_max_length = get_unaligned_le16(&radiotap_header->it_len); 1168c2ecf20Sopenharmony_ci iterator->_arg_index = 0; 1178c2ecf20Sopenharmony_ci iterator->_bitmap_shifter = get_unaligned_le32(&radiotap_header->it_present); 1188c2ecf20Sopenharmony_ci iterator->_arg = (uint8_t *)radiotap_header + sizeof(*radiotap_header); 1198c2ecf20Sopenharmony_ci iterator->_reset_on_ext = 0; 1208c2ecf20Sopenharmony_ci iterator->_next_bitmap = &radiotap_header->it_present; 1218c2ecf20Sopenharmony_ci iterator->_next_bitmap++; 1228c2ecf20Sopenharmony_ci iterator->_vns = vns; 1238c2ecf20Sopenharmony_ci iterator->current_namespace = &radiotap_ns; 1248c2ecf20Sopenharmony_ci iterator->is_radiotap_ns = 1; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci /* find payload start allowing for extended bitmap(s) */ 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci if (iterator->_bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT)) { 1298c2ecf20Sopenharmony_ci if ((unsigned long)iterator->_arg - 1308c2ecf20Sopenharmony_ci (unsigned long)iterator->_rtheader + sizeof(uint32_t) > 1318c2ecf20Sopenharmony_ci (unsigned long)iterator->_max_length) 1328c2ecf20Sopenharmony_ci return -EINVAL; 1338c2ecf20Sopenharmony_ci while (get_unaligned_le32(iterator->_arg) & 1348c2ecf20Sopenharmony_ci (1 << IEEE80211_RADIOTAP_EXT)) { 1358c2ecf20Sopenharmony_ci iterator->_arg += sizeof(uint32_t); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci /* 1388c2ecf20Sopenharmony_ci * check for insanity where the present bitmaps 1398c2ecf20Sopenharmony_ci * keep claiming to extend up to or even beyond the 1408c2ecf20Sopenharmony_ci * stated radiotap header length 1418c2ecf20Sopenharmony_ci */ 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci if ((unsigned long)iterator->_arg - 1448c2ecf20Sopenharmony_ci (unsigned long)iterator->_rtheader + 1458c2ecf20Sopenharmony_ci sizeof(uint32_t) > 1468c2ecf20Sopenharmony_ci (unsigned long)iterator->_max_length) 1478c2ecf20Sopenharmony_ci return -EINVAL; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci iterator->_arg += sizeof(uint32_t); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci /* 1538c2ecf20Sopenharmony_ci * no need to check again for blowing past stated radiotap 1548c2ecf20Sopenharmony_ci * header length, because ieee80211_radiotap_iterator_next 1558c2ecf20Sopenharmony_ci * checks it before it is dereferenced 1568c2ecf20Sopenharmony_ci */ 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci iterator->this_arg = iterator->_arg; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci /* we are all initialized happily */ 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci return 0; 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ieee80211_radiotap_iterator_init); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_cistatic void find_ns(struct ieee80211_radiotap_iterator *iterator, 1688c2ecf20Sopenharmony_ci uint32_t oui, uint8_t subns) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci int i; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci iterator->current_namespace = NULL; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (!iterator->_vns) 1758c2ecf20Sopenharmony_ci return; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci for (i = 0; i < iterator->_vns->n_ns; i++) { 1788c2ecf20Sopenharmony_ci if (iterator->_vns->ns[i].oui != oui) 1798c2ecf20Sopenharmony_ci continue; 1808c2ecf20Sopenharmony_ci if (iterator->_vns->ns[i].subns != subns) 1818c2ecf20Sopenharmony_ci continue; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci iterator->current_namespace = &iterator->_vns->ns[i]; 1848c2ecf20Sopenharmony_ci break; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci/** 1918c2ecf20Sopenharmony_ci * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg 1928c2ecf20Sopenharmony_ci * @iterator: radiotap_iterator to move to next arg (if any) 1938c2ecf20Sopenharmony_ci * 1948c2ecf20Sopenharmony_ci * Returns: 0 if there is an argument to handle, 1958c2ecf20Sopenharmony_ci * -ENOENT if there are no more args or -EINVAL 1968c2ecf20Sopenharmony_ci * if there is something else wrong. 1978c2ecf20Sopenharmony_ci * 1988c2ecf20Sopenharmony_ci * This function provides the next radiotap arg index (IEEE80211_RADIOTAP_*) 1998c2ecf20Sopenharmony_ci * in @this_arg_index and sets @this_arg to point to the 2008c2ecf20Sopenharmony_ci * payload for the field. It takes care of alignment handling and extended 2018c2ecf20Sopenharmony_ci * present fields. @this_arg can be changed by the caller (eg, 2028c2ecf20Sopenharmony_ci * incremented to move inside a compound argument like 2038c2ecf20Sopenharmony_ci * IEEE80211_RADIOTAP_CHANNEL). The args pointed to are in 2048c2ecf20Sopenharmony_ci * little-endian format whatever the endianess of your CPU. 2058c2ecf20Sopenharmony_ci * 2068c2ecf20Sopenharmony_ci * Alignment Gotcha: 2078c2ecf20Sopenharmony_ci * You must take care when dereferencing iterator.this_arg 2088c2ecf20Sopenharmony_ci * for multibyte types... the pointer is not aligned. Use 2098c2ecf20Sopenharmony_ci * get_unaligned((type *)iterator.this_arg) to dereference 2108c2ecf20Sopenharmony_ci * iterator.this_arg for type "type" safely on all arches. 2118c2ecf20Sopenharmony_ci */ 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ciint ieee80211_radiotap_iterator_next( 2148c2ecf20Sopenharmony_ci struct ieee80211_radiotap_iterator *iterator) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci while (1) { 2178c2ecf20Sopenharmony_ci int hit = 0; 2188c2ecf20Sopenharmony_ci int pad, align, size, subns; 2198c2ecf20Sopenharmony_ci uint32_t oui; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci /* if no more EXT bits, that's it */ 2228c2ecf20Sopenharmony_ci if ((iterator->_arg_index % 32) == IEEE80211_RADIOTAP_EXT && 2238c2ecf20Sopenharmony_ci !(iterator->_bitmap_shifter & 1)) 2248c2ecf20Sopenharmony_ci return -ENOENT; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci if (!(iterator->_bitmap_shifter & 1)) 2278c2ecf20Sopenharmony_ci goto next_entry; /* arg not present */ 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci /* get alignment/size of data */ 2308c2ecf20Sopenharmony_ci switch (iterator->_arg_index % 32) { 2318c2ecf20Sopenharmony_ci case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE: 2328c2ecf20Sopenharmony_ci case IEEE80211_RADIOTAP_EXT: 2338c2ecf20Sopenharmony_ci align = 1; 2348c2ecf20Sopenharmony_ci size = 0; 2358c2ecf20Sopenharmony_ci break; 2368c2ecf20Sopenharmony_ci case IEEE80211_RADIOTAP_VENDOR_NAMESPACE: 2378c2ecf20Sopenharmony_ci align = 2; 2388c2ecf20Sopenharmony_ci size = 6; 2398c2ecf20Sopenharmony_ci break; 2408c2ecf20Sopenharmony_ci default: 2418c2ecf20Sopenharmony_ci if (!iterator->current_namespace || 2428c2ecf20Sopenharmony_ci iterator->_arg_index >= iterator->current_namespace->n_bits) { 2438c2ecf20Sopenharmony_ci if (iterator->current_namespace == &radiotap_ns) 2448c2ecf20Sopenharmony_ci return -ENOENT; 2458c2ecf20Sopenharmony_ci align = 0; 2468c2ecf20Sopenharmony_ci } else { 2478c2ecf20Sopenharmony_ci align = iterator->current_namespace->align_size[iterator->_arg_index].align; 2488c2ecf20Sopenharmony_ci size = iterator->current_namespace->align_size[iterator->_arg_index].size; 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci if (!align) { 2518c2ecf20Sopenharmony_ci /* skip all subsequent data */ 2528c2ecf20Sopenharmony_ci iterator->_arg = iterator->_next_ns_data; 2538c2ecf20Sopenharmony_ci /* give up on this namespace */ 2548c2ecf20Sopenharmony_ci iterator->current_namespace = NULL; 2558c2ecf20Sopenharmony_ci goto next_entry; 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci break; 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci /* 2618c2ecf20Sopenharmony_ci * arg is present, account for alignment padding 2628c2ecf20Sopenharmony_ci * 2638c2ecf20Sopenharmony_ci * Note that these alignments are relative to the start 2648c2ecf20Sopenharmony_ci * of the radiotap header. There is no guarantee 2658c2ecf20Sopenharmony_ci * that the radiotap header itself is aligned on any 2668c2ecf20Sopenharmony_ci * kind of boundary. 2678c2ecf20Sopenharmony_ci * 2688c2ecf20Sopenharmony_ci * The above is why get_unaligned() is used to dereference 2698c2ecf20Sopenharmony_ci * multibyte elements from the radiotap area. 2708c2ecf20Sopenharmony_ci */ 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci pad = ((unsigned long)iterator->_arg - 2738c2ecf20Sopenharmony_ci (unsigned long)iterator->_rtheader) & (align - 1); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci if (pad) 2768c2ecf20Sopenharmony_ci iterator->_arg += align - pad; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci if (iterator->_arg_index % 32 == IEEE80211_RADIOTAP_VENDOR_NAMESPACE) { 2798c2ecf20Sopenharmony_ci int vnslen; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci if ((unsigned long)iterator->_arg + size - 2828c2ecf20Sopenharmony_ci (unsigned long)iterator->_rtheader > 2838c2ecf20Sopenharmony_ci (unsigned long)iterator->_max_length) 2848c2ecf20Sopenharmony_ci return -EINVAL; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci oui = (*iterator->_arg << 16) | 2878c2ecf20Sopenharmony_ci (*(iterator->_arg + 1) << 8) | 2888c2ecf20Sopenharmony_ci *(iterator->_arg + 2); 2898c2ecf20Sopenharmony_ci subns = *(iterator->_arg + 3); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci find_ns(iterator, oui, subns); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci vnslen = get_unaligned_le16(iterator->_arg + 4); 2948c2ecf20Sopenharmony_ci iterator->_next_ns_data = iterator->_arg + size + vnslen; 2958c2ecf20Sopenharmony_ci if (!iterator->current_namespace) 2968c2ecf20Sopenharmony_ci size += vnslen; 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci /* 3008c2ecf20Sopenharmony_ci * this is what we will return to user, but we need to 3018c2ecf20Sopenharmony_ci * move on first so next call has something fresh to test 3028c2ecf20Sopenharmony_ci */ 3038c2ecf20Sopenharmony_ci iterator->this_arg_index = iterator->_arg_index; 3048c2ecf20Sopenharmony_ci iterator->this_arg = iterator->_arg; 3058c2ecf20Sopenharmony_ci iterator->this_arg_size = size; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci /* internally move on the size of this arg */ 3088c2ecf20Sopenharmony_ci iterator->_arg += size; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci /* 3118c2ecf20Sopenharmony_ci * check for insanity where we are given a bitmap that 3128c2ecf20Sopenharmony_ci * claims to have more arg content than the length of the 3138c2ecf20Sopenharmony_ci * radiotap section. We will normally end up equalling this 3148c2ecf20Sopenharmony_ci * max_length on the last arg, never exceeding it. 3158c2ecf20Sopenharmony_ci */ 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci if ((unsigned long)iterator->_arg - 3188c2ecf20Sopenharmony_ci (unsigned long)iterator->_rtheader > 3198c2ecf20Sopenharmony_ci (unsigned long)iterator->_max_length) 3208c2ecf20Sopenharmony_ci return -EINVAL; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci /* these special ones are valid in each bitmap word */ 3238c2ecf20Sopenharmony_ci switch (iterator->_arg_index % 32) { 3248c2ecf20Sopenharmony_ci case IEEE80211_RADIOTAP_VENDOR_NAMESPACE: 3258c2ecf20Sopenharmony_ci iterator->_reset_on_ext = 1; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci iterator->is_radiotap_ns = 0; 3288c2ecf20Sopenharmony_ci /* 3298c2ecf20Sopenharmony_ci * If parser didn't register this vendor 3308c2ecf20Sopenharmony_ci * namespace with us, allow it to show it 3318c2ecf20Sopenharmony_ci * as 'raw. Do do that, set argument index 3328c2ecf20Sopenharmony_ci * to vendor namespace. 3338c2ecf20Sopenharmony_ci */ 3348c2ecf20Sopenharmony_ci iterator->this_arg_index = 3358c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_VENDOR_NAMESPACE; 3368c2ecf20Sopenharmony_ci if (!iterator->current_namespace) 3378c2ecf20Sopenharmony_ci hit = 1; 3388c2ecf20Sopenharmony_ci goto next_entry; 3398c2ecf20Sopenharmony_ci case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE: 3408c2ecf20Sopenharmony_ci iterator->_reset_on_ext = 1; 3418c2ecf20Sopenharmony_ci iterator->current_namespace = &radiotap_ns; 3428c2ecf20Sopenharmony_ci iterator->is_radiotap_ns = 1; 3438c2ecf20Sopenharmony_ci goto next_entry; 3448c2ecf20Sopenharmony_ci case IEEE80211_RADIOTAP_EXT: 3458c2ecf20Sopenharmony_ci /* 3468c2ecf20Sopenharmony_ci * bit 31 was set, there is more 3478c2ecf20Sopenharmony_ci * -- move to next u32 bitmap 3488c2ecf20Sopenharmony_ci */ 3498c2ecf20Sopenharmony_ci iterator->_bitmap_shifter = 3508c2ecf20Sopenharmony_ci get_unaligned_le32(iterator->_next_bitmap); 3518c2ecf20Sopenharmony_ci iterator->_next_bitmap++; 3528c2ecf20Sopenharmony_ci if (iterator->_reset_on_ext) 3538c2ecf20Sopenharmony_ci iterator->_arg_index = 0; 3548c2ecf20Sopenharmony_ci else 3558c2ecf20Sopenharmony_ci iterator->_arg_index++; 3568c2ecf20Sopenharmony_ci iterator->_reset_on_ext = 0; 3578c2ecf20Sopenharmony_ci break; 3588c2ecf20Sopenharmony_ci default: 3598c2ecf20Sopenharmony_ci /* we've got a hit! */ 3608c2ecf20Sopenharmony_ci hit = 1; 3618c2ecf20Sopenharmony_ci next_entry: 3628c2ecf20Sopenharmony_ci iterator->_bitmap_shifter >>= 1; 3638c2ecf20Sopenharmony_ci iterator->_arg_index++; 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci /* if we found a valid arg earlier, return it now */ 3678c2ecf20Sopenharmony_ci if (hit) 3688c2ecf20Sopenharmony_ci return 0; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ieee80211_radiotap_iterator_next); 372