18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* 28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Radiotap parser 38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright 2007 Andy Green <andy@warmcat.com> 58d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 68d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This program is free software; you can redistribute it and/or modify 78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * it under the terms of the GNU General Public License version 2 as 88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * published by the Free Software Foundation. 98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Alternatively, this software may be distributed under the terms of BSD 118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * license. 128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * See README and COPYING for more details. 148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Modified for userspace by Johannes Berg <johannes@sipsolutions.net> 178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * I only modified some things on top to ease syncing should bugs be found. 188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h" 218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h" 238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "radiotap_iter.h" 248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define le16_to_cpu le_to_host16 268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define le32_to_cpu le_to_host32 278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define __le32 uint32_t 288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define ulong unsigned long 298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define unlikely(cond) (cond) 308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define get_unaligned(p) \ 318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt({ \ 328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct packed_dummy_struct { \ 338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt typeof(*(p)) __val; \ 348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } __attribute__((packed)) *__ptr = (void *) (p); \ 358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt \ 368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt __ptr->__val; \ 378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}) 388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* function prototypes and related defs are in radiotap_iter.h */ 408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * ieee80211_radiotap_iterator_init - radiotap parser iterator initialization 438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @iterator: radiotap_iterator to initialize 448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @radiotap_header: radiotap header to parse 458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @max_length: total length we can parse into (eg, whole packet length) 468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 or a negative error code if there is a problem. 488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This function initializes an opaque iterator struct which can then 508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * be passed to ieee80211_radiotap_iterator_next() to visit every radiotap 518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * argument which is present in the header. It knows about extended 528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * present headers and handles them. 538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * How to use: 558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator 568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * struct ieee80211_radiotap_iterator (no need to init the struct beforehand) 578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * checking for a good 0 return code. Then loop calling 588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * __ieee80211_radiotap_iterator_next()... it returns either 0, 598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * -ENOENT if there are no more args to parse, or -EINVAL if there is a problem. 608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * The iterator's @this_arg member points to the start of the argument 618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * associated with the current argument index that is present, which can be 628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * found in the iterator's @this_arg_index member. This arg index corresponds 638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * to the IEEE80211_RADIOTAP_... defines. 648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Radiotap header length: 668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * You can find the CPU-endian total radiotap header length in 678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * iterator->max_length after executing ieee80211_radiotap_iterator_init() 688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * successfully. 698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Alignment Gotcha: 718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * You must take care when dereferencing iterator.this_arg 728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * for multibyte types... the pointer is not aligned. Use 738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * get_unaligned((type *)iterator.this_arg) to dereference 748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * iterator.this_arg for type "type" safely on all arches. 758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Example code: 778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * See Documentation/networking/radiotap-headers.txt 788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ieee80211_radiotap_iterator_init( 818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ieee80211_radiotap_iterator *iterator, 828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ieee80211_radiotap_header *radiotap_header, 838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int max_length) 848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Linux only supports version 0 radiotap format */ 868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (radiotap_header->it_version) 878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -EINVAL; 888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* sanity check for allowed length and radiotap length field */ 908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (max_length < le16_to_cpu(get_unaligned(&radiotap_header->it_len))) 918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -EINVAL; 928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iterator->rtheader = radiotap_header; 948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iterator->max_length = le16_to_cpu(get_unaligned( 958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &radiotap_header->it_len)); 968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iterator->arg_index = 0; 978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iterator->bitmap_shifter = le32_to_cpu(get_unaligned( 988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &radiotap_header->it_present)); 998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iterator->arg = (u8 *)radiotap_header + sizeof(*radiotap_header); 1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iterator->this_arg = NULL; 1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* find payload start allowing for extended bitmap(s) */ 1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (unlikely(iterator->bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT))) { 1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (le32_to_cpu(get_unaligned((__le32 *)iterator->arg)) & 1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (1<<IEEE80211_RADIOTAP_EXT)) { 1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iterator->arg += sizeof(u32); 1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * check for insanity where the present bitmaps 1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * keep claiming to extend up to or even beyond the 1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * stated radiotap header length 1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (((ulong)iterator->arg - (ulong)iterator->rtheader) 1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt > (ulong)iterator->max_length) 1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -EINVAL; 1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iterator->arg += sizeof(u32); 1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * no need to check again for blowing past stated radiotap 1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * header length, because ieee80211_radiotap_iterator_next 1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * checks it before it is dereferenced 1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* we are all initialized happily */ 1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg 1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @iterator: radiotap_iterator to move to next arg (if any) 1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 if there is an argument to handle, 1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * -ENOENT if there are no more args or -EINVAL 1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * if there is something else wrong. 1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This function provides the next radiotap arg index (IEEE80211_RADIOTAP_*) 1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * in @this_arg_index and sets @this_arg to point to the 1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * payload for the field. It takes care of alignment handling and extended 1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * present fields. @this_arg can be changed by the caller (eg, 1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * incremented to move inside a compound argument like 1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * IEEE80211_RADIOTAP_CHANNEL). The args pointed to are in 1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * little-endian format whatever the endianess of your CPU. 1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Alignment Gotcha: 1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * You must take care when dereferencing iterator.this_arg 1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * for multibyte types... the pointer is not aligned. Use 1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * get_unaligned((type *)iterator.this_arg) to dereference 1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * iterator.this_arg for type "type" safely on all arches. 1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ieee80211_radiotap_iterator_next( 1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ieee80211_radiotap_iterator *iterator) 1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * small length lookup table for all radiotap types we heard of 1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * starting from b0 in the bitmap, so we can walk the payload 1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * area of the radiotap header 1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * There is a requirement to pad args, so that args 1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * of a given length must begin at a boundary of that length 1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * -- but note that compound args are allowed (eg, 2 x u16 1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * for IEEE80211_RADIOTAP_CHANNEL) so total arg length is not 1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * a reliable indicator of alignment requirement. 1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * upper nybble: content alignment for arg 1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * lower nybble: content length for arg 1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt static const u8 rt_sizes[] = { 1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt [IEEE80211_RADIOTAP_TSFT] = 0x88, 1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt [IEEE80211_RADIOTAP_FLAGS] = 0x11, 1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt [IEEE80211_RADIOTAP_RATE] = 0x11, 1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt [IEEE80211_RADIOTAP_CHANNEL] = 0x24, 1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt [IEEE80211_RADIOTAP_FHSS] = 0x22, 1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = 0x11, 1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt [IEEE80211_RADIOTAP_DBM_ANTNOISE] = 0x11, 1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt [IEEE80211_RADIOTAP_LOCK_QUALITY] = 0x22, 1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt [IEEE80211_RADIOTAP_TX_ATTENUATION] = 0x22, 1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = 0x22, 1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt [IEEE80211_RADIOTAP_DBM_TX_POWER] = 0x11, 1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt [IEEE80211_RADIOTAP_ANTENNA] = 0x11, 1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = 0x11, 1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt [IEEE80211_RADIOTAP_DB_ANTNOISE] = 0x11, 1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt [IEEE80211_RADIOTAP_RX_FLAGS] = 0x22, 1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt [IEEE80211_RADIOTAP_TX_FLAGS] = 0x22, 1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt [IEEE80211_RADIOTAP_RTS_RETRIES] = 0x11, 1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt [IEEE80211_RADIOTAP_DATA_RETRIES] = 0x11, 1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * add more here as they are defined in 1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * include/net/ieee80211_radiotap.h 1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt }; 2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * for every radiotap entry we can at 2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * least skip (by knowing the length)... 2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (iterator->arg_index < (int) sizeof(rt_sizes)) { 2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int hit = 0; 2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int pad; 2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!(iterator->bitmap_shifter & 1)) 2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto next_entry; /* arg not present */ 2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * arg is present, account for alignment padding 2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 8-bit args can be at any alignment 2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 16-bit args must start on 16-bit boundary 2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 32-bit args must start on 32-bit boundary 2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 64-bit args must start on 64-bit boundary 2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * note that total arg size can differ from alignment of 2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * elements inside arg, so we use upper nybble of length 2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * table to base alignment on 2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * also note: these alignments are ** relative to the 2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * start of the radiotap header **. There is no guarantee 2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * that the radiotap header itself is aligned on any 2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * kind of boundary. 2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * the above is why get_unaligned() is used to dereference 2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * multibyte elements from the radiotap area 2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pad = (((ulong)iterator->arg) - 2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ((ulong)iterator->rtheader)) & 2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ((rt_sizes[iterator->arg_index] >> 4) - 1); 2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pad) 2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iterator->arg += 2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (rt_sizes[iterator->arg_index] >> 4) - pad; 2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * this is what we will return to user, but we need to 2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * move on first so next call has something fresh to test 2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iterator->this_arg_index = iterator->arg_index; 2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iterator->this_arg = iterator->arg; 2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hit = 1; 2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* internally move on the size of this arg */ 2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iterator->arg += rt_sizes[iterator->arg_index] & 0x0f; 2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * check for insanity where we are given a bitmap that 2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * claims to have more arg content than the length of the 2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * radiotap section. We will normally end up equalling this 2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * max_length on the last arg, never exceeding it. 2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (((ulong)iterator->arg - (ulong)iterator->rtheader) > 2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (ulong) iterator->max_length) 2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -EINVAL; 2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_entry: 2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iterator->arg_index++; 2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (unlikely((iterator->arg_index & 31) == 0)) { 2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* completed current u32 bitmap */ 2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iterator->bitmap_shifter & 1) { 2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* b31 was set, there is more */ 2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* move to next u32 bitmap */ 2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iterator->bitmap_shifter = le32_to_cpu( 2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt get_unaligned(iterator->next_bitmap)); 2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iterator->next_bitmap++; 2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else 2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* no more bitmaps: end */ 2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iterator->arg_index = sizeof(rt_sizes); 2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else /* just try the next bit */ 2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iterator->bitmap_shifter >>= 1; 2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* if we found a valid arg earlier, return it now */ 2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hit) 2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* we don't know how to handle any more args, we're done */ 2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -ENOENT; 2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 288