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 */ 167dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt#include "platform.h" 174ae50e65ef0eefe6d5c356acbc1839f8eac68af5Dmitry Shmidt#include "radiotap_iter.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); 112fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt iterator->_next_ns_data = NULL; 1137dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_reset_on_ext = 0; 1147dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_next_bitmap = &radiotap_header->it_present; 1157dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_next_bitmap++; 1167dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_vns = vns; 1177dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->current_namespace = &radiotap_ns; 1187dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->is_radiotap_ns = 1; 1197dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt#ifdef RADIOTAP_SUPPORT_OVERRIDES 1207dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->n_overrides = 0; 1217dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->overrides = NULL; 1227dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt#endif 1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* find payload start allowing for extended bitmap(s) */ 1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 126d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (iterator->_bitmap_shifter & BIT(IEEE80211_RADIOTAP_EXT)) { 1277dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if ((unsigned long)iterator->_arg - 1287dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt (unsigned long)iterator->_rtheader + sizeof(uint32_t) > 1297dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt (unsigned long)iterator->_max_length) 1307dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt return -EINVAL; 1317dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt while (get_unaligned_le32(iterator->_arg) & 132d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt BIT(IEEE80211_RADIOTAP_EXT)) { 1337dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_arg += sizeof(uint32_t); 1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * check for insanity where the present bitmaps 1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * keep claiming to extend up to or even beyond the 1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * stated radiotap header length 1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1417dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if ((unsigned long)iterator->_arg - 1427dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt (unsigned long)iterator->_rtheader + 1437dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt sizeof(uint32_t) > 1447dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt (unsigned long)iterator->_max_length) 1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -EINVAL; 1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1487dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_arg += sizeof(uint32_t); 1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * no need to check again for blowing past stated radiotap 1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * header length, because ieee80211_radiotap_iterator_next 1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * checks it before it is dereferenced 1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1577dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->this_arg = iterator->_arg; 158fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt iterator->this_arg_index = 0; 159fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt iterator->this_arg_size = 0; 1607dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt 1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* we are all initialized happily */ 1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1667dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidtstatic void find_ns(struct ieee80211_radiotap_iterator *iterator, 1677dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt uint32_t oui, uint8_t subns) 1687dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt{ 1697dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt int i; 1707dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt 1717dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->current_namespace = NULL; 1727dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt 1737dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if (!iterator->_vns) 1747dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt return; 1757dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt 1767dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt for (i = 0; i < iterator->_vns->n_ns; i++) { 1777dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if (iterator->_vns->ns[i].oui != oui) 1787dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt continue; 1797dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if (iterator->_vns->ns[i].subns != subns) 1807dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt continue; 1817dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt 1827dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->current_namespace = &iterator->_vns->ns[i]; 1837dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt break; 1847dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt } 1857dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt} 1867dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt 1877dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt#ifdef RADIOTAP_SUPPORT_OVERRIDES 1887dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidtstatic int find_override(struct ieee80211_radiotap_iterator *iterator, 1897dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt int *align, int *size) 1907dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt{ 1917dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt int i; 1927dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt 1937dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if (!iterator->overrides) 1947dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt return 0; 1957dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt 1967dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt for (i = 0; i < iterator->n_overrides; i++) { 1977dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if (iterator->_arg_index == iterator->overrides[i].field) { 1987dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt *align = iterator->overrides[i].align; 1997dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt *size = iterator->overrides[i].size; 2007dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if (!*align) /* erroneous override */ 2017dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt return 0; 2027dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt return 1; 2037dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt } 2047dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt } 2057dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt 2067dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt return 0; 2077dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt} 2087dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt#endif 2097dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt 2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg 2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @iterator: radiotap_iterator to move to next arg (if any) 2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 if there is an argument to handle, 2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * -ENOENT if there are no more args or -EINVAL 2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * if there is something else wrong. 2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This function provides the next radiotap arg index (IEEE80211_RADIOTAP_*) 2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * in @this_arg_index and sets @this_arg to point to the 2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * payload for the field. It takes care of alignment handling and extended 2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * present fields. @this_arg can be changed by the caller (eg, 2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * incremented to move inside a compound argument like 2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * IEEE80211_RADIOTAP_CHANNEL). The args pointed to are in 2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * little-endian format whatever the endianess of your CPU. 2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Alignment Gotcha: 2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * You must take care when dereferencing iterator.this_arg 2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * for multibyte types... the pointer is not aligned. Use 2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * get_unaligned((type *)iterator.this_arg) to dereference 2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * iterator.this_arg for type "type" safely on all arches. 2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ieee80211_radiotap_iterator_next( 2357dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt struct ieee80211_radiotap_iterator *iterator) 2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2377dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt while (1) { 2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int hit = 0; 2397dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt int pad, align, size, subns; 2407dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt uint32_t oui; 2417dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt 2427dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt /* if no more EXT bits, that's it */ 2437dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if ((iterator->_arg_index % 32) == IEEE80211_RADIOTAP_EXT && 2447dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt !(iterator->_bitmap_shifter & 1)) 2457dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt return -ENOENT; 2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2477dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if (!(iterator->_bitmap_shifter & 1)) 2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto next_entry; /* arg not present */ 2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2507dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt /* get alignment/size of data */ 2517dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt switch (iterator->_arg_index % 32) { 2527dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE: 2537dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt case IEEE80211_RADIOTAP_EXT: 2547dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt align = 1; 2557dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt size = 0; 2567dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt break; 2577dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt case IEEE80211_RADIOTAP_VENDOR_NAMESPACE: 2587dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt align = 2; 2597dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt size = 6; 2607dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt break; 2617dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt default: 2627dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt#ifdef RADIOTAP_SUPPORT_OVERRIDES 2637dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if (find_override(iterator, &align, &size)) { 2647dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt /* all set */ 2657dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt } else 2667dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt#endif 2677dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if (!iterator->current_namespace || 2687dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_arg_index >= iterator->current_namespace->n_bits) { 2697dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if (iterator->current_namespace == &radiotap_ns) 2707dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt return -ENOENT; 2717dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt align = 0; 2727dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt } else { 2737dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt align = iterator->current_namespace->align_size[iterator->_arg_index].align; 2747dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt size = iterator->current_namespace->align_size[iterator->_arg_index].size; 2757dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt } 2767dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if (!align) { 2777dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt /* skip all subsequent data */ 2787dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_arg = iterator->_next_ns_data; 2797dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt /* give up on this namespace */ 2807dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->current_namespace = NULL; 2817dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt goto next_entry; 2827dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt } 2837dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt break; 2847dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt } 2857dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt 2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * arg is present, account for alignment padding 2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 2897dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt * Note that these alignments are relative to the start 2907dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt * of the radiotap header. There is no guarantee 2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * that the radiotap header itself is aligned on any 2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * kind of boundary. 2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 2947dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt * The above is why get_unaligned() is used to dereference 2957dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt * multibyte elements from the radiotap area. 2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2987dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt pad = ((unsigned long)iterator->_arg - 2997dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt (unsigned long)iterator->_rtheader) & (align - 1); 3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pad) 3027dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_arg += align - pad; 3037dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt 3047dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if (iterator->_arg_index % 32 == IEEE80211_RADIOTAP_VENDOR_NAMESPACE) { 3057dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt int vnslen; 3067dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt 3077dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if ((unsigned long)iterator->_arg + size - 3087dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt (unsigned long)iterator->_rtheader > 3097dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt (unsigned long)iterator->_max_length) 3107dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt return -EINVAL; 3117dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt 3127dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt oui = (*iterator->_arg << 16) | 3137dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt (*(iterator->_arg + 1) << 8) | 3147dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt *(iterator->_arg + 2); 3157dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt subns = *(iterator->_arg + 3); 3167dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt 3177dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt find_ns(iterator, oui, subns); 3187dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt 3197dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt vnslen = get_unaligned_le16(iterator->_arg + 4); 3207dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_next_ns_data = iterator->_arg + size + vnslen; 3217dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if (!iterator->current_namespace) 3227dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt size += vnslen; 3237dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt } 3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * this is what we will return to user, but we need to 3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * move on first so next call has something fresh to test 3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 3297dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->this_arg_index = iterator->_arg_index; 3307dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->this_arg = iterator->_arg; 3317dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->this_arg_size = size; 3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* internally move on the size of this arg */ 3347dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_arg += size; 3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * check for insanity where we are given a bitmap that 3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * claims to have more arg content than the length of the 3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * radiotap section. We will normally end up equalling this 3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * max_length on the last arg, never exceeding it. 3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3437dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if ((unsigned long)iterator->_arg - 3447dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt (unsigned long)iterator->_rtheader > 3457dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt (unsigned long)iterator->_max_length) 3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -EINVAL; 3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3487dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt /* these special ones are valid in each bitmap word */ 3497dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt switch (iterator->_arg_index % 32) { 3507dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt case IEEE80211_RADIOTAP_VENDOR_NAMESPACE: 3517dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_reset_on_ext = 1; 3527dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt 3537dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->is_radiotap_ns = 0; 3547dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt /* 3557dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt * If parser didn't register this vendor 3567dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt * namespace with us, allow it to show it 3577dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt * as 'raw. Do do that, set argument index 3587dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt * to vendor namespace. 3597dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt */ 3607dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->this_arg_index = 3617dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt IEEE80211_RADIOTAP_VENDOR_NAMESPACE; 3627dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if (!iterator->current_namespace) 3637dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt hit = 1; 3647dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt goto next_entry; 3657dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE: 3667dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_reset_on_ext = 1; 3677dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->current_namespace = &radiotap_ns; 3687dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->is_radiotap_ns = 1; 3697dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt goto next_entry; 3707dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt case IEEE80211_RADIOTAP_EXT: 3717dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt /* 3727dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt * bit 31 was set, there is more 3737dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt * -- move to next u32 bitmap 3747dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt */ 3757dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_bitmap_shifter = 3767dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt get_unaligned_le32(iterator->_next_bitmap); 3777dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_next_bitmap++; 3787dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt if (iterator->_reset_on_ext) 3797dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_arg_index = 0; 3807dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt else 3817dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_arg_index++; 3827dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_reset_on_ext = 0; 3837dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt break; 3847dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt default: 3857dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt /* we've got a hit! */ 3867dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt hit = 1; 3877dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt next_entry: 3887dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_bitmap_shifter >>= 1; 3897dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt iterator->_arg_index++; 3907dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt } 3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* if we found a valid arg earlier, return it now */ 3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hit) 3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 397