18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* 28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Radiotap parser 38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright 2007 Andy Green <andy@warmcat.com> 57dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt * Copyright 2009 Johannes Berg <johannes@sipsolutions.net> 68d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This program is free software; you can redistribute it and/or modify 88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * it under the terms of the GNU General Public License version 2 as 98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * published by the Free Software Foundation. 108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Alternatively, this software may be distributed under the terms of BSD 128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * license. 138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 147dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt * See COPYING for more details. 158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "radiotap_iter.h" 177dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt#include "platform.h" 188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* function prototypes and related defs are in radiotap_iter.h */ 208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 217dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidtstatic const struct radiotap_align_size rtap_namespace_sizes[] = { 227dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt [IEEE80211_RADIOTAP_TSFT] = { .align = 8, .size = 8, }, 237dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt [IEEE80211_RADIOTAP_FLAGS] = { .align = 1, .size = 1, }, 247dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt [IEEE80211_RADIOTAP_RATE] = { .align = 1, .size = 1, }, 257dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt [IEEE80211_RADIOTAP_CHANNEL] = { .align = 2, .size = 4, }, 267dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt [IEEE80211_RADIOTAP_FHSS] = { .align = 2, .size = 2, }, 277dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = { .align = 1, .size = 1, }, 287dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt [IEEE80211_RADIOTAP_DBM_ANTNOISE] = { .align = 1, .size = 1, }, 297dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt [IEEE80211_RADIOTAP_LOCK_QUALITY] = { .align = 2, .size = 2, }, 307dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt [IEEE80211_RADIOTAP_TX_ATTENUATION] = { .align = 2, .size = 2, }, 317dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = { .align = 2, .size = 2, }, 327dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt [IEEE80211_RADIOTAP_DBM_TX_POWER] = { .align = 1, .size = 1, }, 337dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt [IEEE80211_RADIOTAP_ANTENNA] = { .align = 1, .size = 1, }, 347dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = { .align = 1, .size = 1, }, 357dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt [IEEE80211_RADIOTAP_DB_ANTNOISE] = { .align = 1, .size = 1, }, 367dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt [IEEE80211_RADIOTAP_RX_FLAGS] = { .align = 2, .size = 2, }, 377dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt [IEEE80211_RADIOTAP_TX_FLAGS] = { .align = 2, .size = 2, }, 387dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt [IEEE80211_RADIOTAP_RTS_RETRIES] = { .align = 1, .size = 1, }, 397dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt [IEEE80211_RADIOTAP_DATA_RETRIES] = { .align = 1, .size = 1, }, 407dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt [IEEE80211_RADIOTAP_MCS] = { .align = 1, .size = 3, }, 417dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt [IEEE80211_RADIOTAP_AMPDU_STATUS] = { .align = 4, .size = 8, }, 427dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt /* 437dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt * add more here as they are defined in radiotap.h 447dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt */ 457dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt}; 467dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt 477dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidtstatic const struct ieee80211_radiotap_namespace radiotap_ns = { 487dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt .n_bits = sizeof(rtap_namespace_sizes) / sizeof(rtap_namespace_sizes[0]), 497dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt .align_size = rtap_namespace_sizes, 507dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt}; 517dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt 528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * ieee80211_radiotap_iterator_init - radiotap parser iterator initialization 548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @iterator: radiotap_iterator to initialize 558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @radiotap_header: radiotap header to parse 568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @max_length: total length we can parse into (eg, whole packet length) 578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 or a negative error code if there is a problem. 598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This function initializes an opaque iterator struct which can then 618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * be passed to ieee80211_radiotap_iterator_next() to visit every radiotap 628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * argument which is present in the header. It knows about extended 638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * present headers and handles them. 648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * How to use: 668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator 678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * struct ieee80211_radiotap_iterator (no need to init the struct beforehand) 688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * checking for a good 0 return code. Then loop calling 698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * __ieee80211_radiotap_iterator_next()... it returns either 0, 708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * -ENOENT if there are no more args to parse, or -EINVAL if there is a problem. 718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * The iterator's @this_arg member points to the start of the argument 728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * associated with the current argument index that is present, which can be 738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * found in the iterator's @this_arg_index member. This arg index corresponds 748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * to the IEEE80211_RADIOTAP_... defines. 758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Radiotap header length: 778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * You can find the CPU-endian total radiotap header length in 788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * iterator->max_length after executing ieee80211_radiotap_iterator_init() 798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * successfully. 808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Alignment Gotcha: 828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * You must take care when dereferencing iterator.this_arg 838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * for multibyte types... the pointer is not aligned. Use 848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * get_unaligned((type *)iterator.this_arg) to dereference 858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * iterator.this_arg for type "type" safely on all arches. 868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 877dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt * Example code: parse.c 888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ieee80211_radiotap_iterator_init( 917dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt struct ieee80211_radiotap_iterator *iterator, 927dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt struct ieee80211_radiotap_header *radiotap_header, 937dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt int max_length, const struct ieee80211_radiotap_vendor_namespaces *vns) 948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 957dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt /* must at least have the radiotap header */ 967dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if (max_length < (int)sizeof(struct ieee80211_radiotap_header)) 977dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt return -EINVAL; 987dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt 998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Linux only supports version 0 radiotap format */ 1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (radiotap_header->it_version) 1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -EINVAL; 1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* sanity check for allowed length and radiotap length field */ 1047dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if (max_length < get_unaligned_le16(&radiotap_header->it_len)) 1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -EINVAL; 1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1077dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_rtheader = radiotap_header; 1087dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_max_length = get_unaligned_le16(&radiotap_header->it_len); 1097dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_arg_index = 0; 1107dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_bitmap_shifter = get_unaligned_le32(&radiotap_header->it_present); 1117dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_arg = (uint8_t *)radiotap_header + sizeof(*radiotap_header); 1127dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_reset_on_ext = 0; 1137dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_next_bitmap = &radiotap_header->it_present; 1147dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_next_bitmap++; 1157dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_vns = vns; 1167dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->current_namespace = &radiotap_ns; 1177dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->is_radiotap_ns = 1; 1187dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt#ifdef RADIOTAP_SUPPORT_OVERRIDES 1197dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->n_overrides = 0; 1207dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->overrides = NULL; 1217dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt#endif 1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* find payload start allowing for extended bitmap(s) */ 1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1257dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if (iterator->_bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT)) { 1267dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if ((unsigned long)iterator->_arg - 1277dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt (unsigned long)iterator->_rtheader + sizeof(uint32_t) > 1287dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt (unsigned long)iterator->_max_length) 1297dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt return -EINVAL; 1307dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt while (get_unaligned_le32(iterator->_arg) & 1317dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt (1 << IEEE80211_RADIOTAP_EXT)) { 1327dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_arg += sizeof(uint32_t); 1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * check for insanity where the present bitmaps 1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * keep claiming to extend up to or even beyond the 1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * stated radiotap header length 1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1407dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if ((unsigned long)iterator->_arg - 1417dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt (unsigned long)iterator->_rtheader + 1427dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt sizeof(uint32_t) > 1437dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt (unsigned long)iterator->_max_length) 1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -EINVAL; 1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1477dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_arg += sizeof(uint32_t); 1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * no need to check again for blowing past stated radiotap 1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * header length, because ieee80211_radiotap_iterator_next 1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * checks it before it is dereferenced 1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1567dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->this_arg = iterator->_arg; 1577dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt 1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* we are all initialized happily */ 1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1637dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidtstatic void find_ns(struct ieee80211_radiotap_iterator *iterator, 1647dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt uint32_t oui, uint8_t subns) 1657dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt{ 1667dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt int i; 1677dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt 1687dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->current_namespace = NULL; 1697dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt 1707dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if (!iterator->_vns) 1717dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt return; 1727dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt 1737dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt for (i = 0; i < iterator->_vns->n_ns; i++) { 1747dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if (iterator->_vns->ns[i].oui != oui) 1757dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt continue; 1767dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if (iterator->_vns->ns[i].subns != subns) 1777dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt continue; 1787dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt 1797dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->current_namespace = &iterator->_vns->ns[i]; 1807dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt break; 1817dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt } 1827dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt} 1837dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt 1847dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt#ifdef RADIOTAP_SUPPORT_OVERRIDES 1857dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidtstatic int find_override(struct ieee80211_radiotap_iterator *iterator, 1867dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt int *align, int *size) 1877dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt{ 1887dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt int i; 1897dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt 1907dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if (!iterator->overrides) 1917dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt return 0; 1927dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt 1937dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt for (i = 0; i < iterator->n_overrides; i++) { 1947dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if (iterator->_arg_index == iterator->overrides[i].field) { 1957dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt *align = iterator->overrides[i].align; 1967dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt *size = iterator->overrides[i].size; 1977dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if (!*align) /* erroneous override */ 1987dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt return 0; 1997dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt return 1; 2007dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt } 2017dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt } 2027dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt 2037dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt return 0; 2047dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt} 2057dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt#endif 2067dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt 2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg 2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @iterator: radiotap_iterator to move to next arg (if any) 2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 if there is an argument to handle, 2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * -ENOENT if there are no more args or -EINVAL 2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * if there is something else wrong. 2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This function provides the next radiotap arg index (IEEE80211_RADIOTAP_*) 2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * in @this_arg_index and sets @this_arg to point to the 2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * payload for the field. It takes care of alignment handling and extended 2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * present fields. @this_arg can be changed by the caller (eg, 2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * incremented to move inside a compound argument like 2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * IEEE80211_RADIOTAP_CHANNEL). The args pointed to are in 2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * little-endian format whatever the endianess of your CPU. 2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Alignment Gotcha: 2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * You must take care when dereferencing iterator.this_arg 2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * for multibyte types... the pointer is not aligned. Use 2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * get_unaligned((type *)iterator.this_arg) to dereference 2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * iterator.this_arg for type "type" safely on all arches. 2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ieee80211_radiotap_iterator_next( 2327dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt struct ieee80211_radiotap_iterator *iterator) 2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2347dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt while (1) { 2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int hit = 0; 2367dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt int pad, align, size, subns; 2377dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt uint32_t oui; 2387dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt 2397dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt /* if no more EXT bits, that's it */ 2407dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if ((iterator->_arg_index % 32) == IEEE80211_RADIOTAP_EXT && 2417dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt !(iterator->_bitmap_shifter & 1)) 2427dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt return -ENOENT; 2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2447dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if (!(iterator->_bitmap_shifter & 1)) 2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto next_entry; /* arg not present */ 2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2477dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt /* get alignment/size of data */ 2487dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt switch (iterator->_arg_index % 32) { 2497dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE: 2507dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt case IEEE80211_RADIOTAP_EXT: 2517dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt align = 1; 2527dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt size = 0; 2537dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt break; 2547dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt case IEEE80211_RADIOTAP_VENDOR_NAMESPACE: 2557dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt align = 2; 2567dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt size = 6; 2577dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt break; 2587dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt default: 2597dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt#ifdef RADIOTAP_SUPPORT_OVERRIDES 2607dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if (find_override(iterator, &align, &size)) { 2617dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt /* all set */ 2627dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt } else 2637dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt#endif 2647dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if (!iterator->current_namespace || 2657dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_arg_index >= iterator->current_namespace->n_bits) { 2667dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if (iterator->current_namespace == &radiotap_ns) 2677dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt return -ENOENT; 2687dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt align = 0; 2697dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt } else { 2707dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt align = iterator->current_namespace->align_size[iterator->_arg_index].align; 2717dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt size = iterator->current_namespace->align_size[iterator->_arg_index].size; 2727dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt } 2737dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if (!align) { 2747dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt /* skip all subsequent data */ 2757dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_arg = iterator->_next_ns_data; 2767dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt /* give up on this namespace */ 2777dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->current_namespace = NULL; 2787dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt goto next_entry; 2797dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt } 2807dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt break; 2817dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt } 2827dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt 2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * arg is present, account for alignment padding 2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 2867dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt * Note that these alignments are relative to the start 2877dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt * of the radiotap header. There is no guarantee 2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * that the radiotap header itself is aligned on any 2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * kind of boundary. 2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 2917dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt * The above is why get_unaligned() is used to dereference 2927dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt * multibyte elements from the radiotap area. 2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2957dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt pad = ((unsigned long)iterator->_arg - 2967dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt (unsigned long)iterator->_rtheader) & (align - 1); 2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pad) 2997dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_arg += align - pad; 3007dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt 3017dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if (iterator->_arg_index % 32 == IEEE80211_RADIOTAP_VENDOR_NAMESPACE) { 3027dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt int vnslen; 3037dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt 3047dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if ((unsigned long)iterator->_arg + size - 3057dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt (unsigned long)iterator->_rtheader > 3067dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt (unsigned long)iterator->_max_length) 3077dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt return -EINVAL; 3087dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt 3097dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt oui = (*iterator->_arg << 16) | 3107dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt (*(iterator->_arg + 1) << 8) | 3117dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt *(iterator->_arg + 2); 3127dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt subns = *(iterator->_arg + 3); 3137dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt 3147dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt find_ns(iterator, oui, subns); 3157dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt 3167dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt vnslen = get_unaligned_le16(iterator->_arg + 4); 3177dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_next_ns_data = iterator->_arg + size + vnslen; 3187dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if (!iterator->current_namespace) 3197dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt size += vnslen; 3207dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt } 3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * this is what we will return to user, but we need to 3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * move on first so next call has something fresh to test 3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 3267dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->this_arg_index = iterator->_arg_index; 3277dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->this_arg = iterator->_arg; 3287dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->this_arg_size = size; 3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* internally move on the size of this arg */ 3317dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_arg += size; 3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * check for insanity where we are given a bitmap that 3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * claims to have more arg content than the length of the 3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * radiotap section. We will normally end up equalling this 3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * max_length on the last arg, never exceeding it. 3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3407dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if ((unsigned long)iterator->_arg - 3417dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt (unsigned long)iterator->_rtheader > 3427dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt (unsigned long)iterator->_max_length) 3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -EINVAL; 3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3457dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt /* these special ones are valid in each bitmap word */ 3467dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt switch (iterator->_arg_index % 32) { 3477dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt case IEEE80211_RADIOTAP_VENDOR_NAMESPACE: 3487dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_reset_on_ext = 1; 3497dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt 3507dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->is_radiotap_ns = 0; 3517dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt /* 3527dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt * If parser didn't register this vendor 3537dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt * namespace with us, allow it to show it 3547dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt * as 'raw. Do do that, set argument index 3557dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt * to vendor namespace. 3567dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt */ 3577dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->this_arg_index = 3587dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt IEEE80211_RADIOTAP_VENDOR_NAMESPACE; 3597dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if (!iterator->current_namespace) 3607dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt hit = 1; 3617dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt goto next_entry; 3627dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE: 3637dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_reset_on_ext = 1; 3647dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->current_namespace = &radiotap_ns; 3657dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->is_radiotap_ns = 1; 3667dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt goto next_entry; 3677dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt case IEEE80211_RADIOTAP_EXT: 3687dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt /* 3697dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt * bit 31 was set, there is more 3707dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt * -- move to next u32 bitmap 3717dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt */ 3727dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_bitmap_shifter = 3737dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt get_unaligned_le32(iterator->_next_bitmap); 3747dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_next_bitmap++; 3757dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if (iterator->_reset_on_ext) 3767dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_arg_index = 0; 3777dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt else 3787dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_arg_index++; 3797dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_reset_on_ext = 0; 3807dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt break; 3817dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt default: 3827dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt /* we've got a hit! */ 3837dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt hit = 1; 3847dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt next_entry: 3857dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_bitmap_shifter >>= 1; 3867dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_arg_index++; 3877dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt } 3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* if we found a valid arg earlier, return it now */ 3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hit) 3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 394