18dbcf02cSchristos /* 28dbcf02cSchristos * Radiotap parser 38dbcf02cSchristos * 48dbcf02cSchristos * Copyright 2007 Andy Green <andy@warmcat.com> 53c260e60Schristos * Copyright 2009 Johannes Berg <johannes@sipsolutions.net> 68dbcf02cSchristos * 78dbcf02cSchristos * This program is free software; you can redistribute it and/or modify 88dbcf02cSchristos * it under the terms of the GNU General Public License version 2 as 98dbcf02cSchristos * published by the Free Software Foundation. 108dbcf02cSchristos * 11*bb618362Schristos * Alternatively, this software may be distributed under the terms of ISC 12*bb618362Schristos * license, see COPYING for more details. 138dbcf02cSchristos */ 143c260e60Schristos #include "platform.h" 1536ebd06eSchristos #include "radiotap_iter.h" 168dbcf02cSchristos 178dbcf02cSchristos /* function prototypes and related defs are in radiotap_iter.h */ 188dbcf02cSchristos 193c260e60Schristos static const struct radiotap_align_size rtap_namespace_sizes[] = { 203c260e60Schristos [IEEE80211_RADIOTAP_TSFT] = { .align = 8, .size = 8, }, 213c260e60Schristos [IEEE80211_RADIOTAP_FLAGS] = { .align = 1, .size = 1, }, 223c260e60Schristos [IEEE80211_RADIOTAP_RATE] = { .align = 1, .size = 1, }, 233c260e60Schristos [IEEE80211_RADIOTAP_CHANNEL] = { .align = 2, .size = 4, }, 243c260e60Schristos [IEEE80211_RADIOTAP_FHSS] = { .align = 2, .size = 2, }, 253c260e60Schristos [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = { .align = 1, .size = 1, }, 263c260e60Schristos [IEEE80211_RADIOTAP_DBM_ANTNOISE] = { .align = 1, .size = 1, }, 273c260e60Schristos [IEEE80211_RADIOTAP_LOCK_QUALITY] = { .align = 2, .size = 2, }, 283c260e60Schristos [IEEE80211_RADIOTAP_TX_ATTENUATION] = { .align = 2, .size = 2, }, 293c260e60Schristos [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = { .align = 2, .size = 2, }, 303c260e60Schristos [IEEE80211_RADIOTAP_DBM_TX_POWER] = { .align = 1, .size = 1, }, 313c260e60Schristos [IEEE80211_RADIOTAP_ANTENNA] = { .align = 1, .size = 1, }, 323c260e60Schristos [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = { .align = 1, .size = 1, }, 333c260e60Schristos [IEEE80211_RADIOTAP_DB_ANTNOISE] = { .align = 1, .size = 1, }, 343c260e60Schristos [IEEE80211_RADIOTAP_RX_FLAGS] = { .align = 2, .size = 2, }, 353c260e60Schristos [IEEE80211_RADIOTAP_TX_FLAGS] = { .align = 2, .size = 2, }, 363c260e60Schristos [IEEE80211_RADIOTAP_RTS_RETRIES] = { .align = 1, .size = 1, }, 373c260e60Schristos [IEEE80211_RADIOTAP_DATA_RETRIES] = { .align = 1, .size = 1, }, 383c260e60Schristos [IEEE80211_RADIOTAP_MCS] = { .align = 1, .size = 3, }, 393c260e60Schristos [IEEE80211_RADIOTAP_AMPDU_STATUS] = { .align = 4, .size = 8, }, 40*bb618362Schristos [IEEE80211_RADIOTAP_VHT] = { .align = 2, .size = 12, }, 41*bb618362Schristos [IEEE80211_RADIOTAP_TIMESTAMP] = { .align = 8, .size = 12, }, 423c260e60Schristos /* 433c260e60Schristos * add more here as they are defined in radiotap.h 443c260e60Schristos */ 453c260e60Schristos }; 463c260e60Schristos 473c260e60Schristos static const struct ieee80211_radiotap_namespace radiotap_ns = { 483c260e60Schristos .n_bits = sizeof(rtap_namespace_sizes) / sizeof(rtap_namespace_sizes[0]), 493c260e60Schristos .align_size = rtap_namespace_sizes, 503c260e60Schristos }; 513c260e60Schristos 528dbcf02cSchristos /** 538dbcf02cSchristos * ieee80211_radiotap_iterator_init - radiotap parser iterator initialization 548dbcf02cSchristos * @iterator: radiotap_iterator to initialize 558dbcf02cSchristos * @radiotap_header: radiotap header to parse 568dbcf02cSchristos * @max_length: total length we can parse into (eg, whole packet length) 578dbcf02cSchristos * 588dbcf02cSchristos * Returns: 0 or a negative error code if there is a problem. 598dbcf02cSchristos * 608dbcf02cSchristos * This function initializes an opaque iterator struct which can then 618dbcf02cSchristos * be passed to ieee80211_radiotap_iterator_next() to visit every radiotap 628dbcf02cSchristos * argument which is present in the header. It knows about extended 638dbcf02cSchristos * present headers and handles them. 648dbcf02cSchristos * 658dbcf02cSchristos * How to use: 668dbcf02cSchristos * call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator 678dbcf02cSchristos * struct ieee80211_radiotap_iterator (no need to init the struct beforehand) 688dbcf02cSchristos * checking for a good 0 return code. Then loop calling 698dbcf02cSchristos * __ieee80211_radiotap_iterator_next()... it returns either 0, 708dbcf02cSchristos * -ENOENT if there are no more args to parse, or -EINVAL if there is a problem. 718dbcf02cSchristos * The iterator's @this_arg member points to the start of the argument 728dbcf02cSchristos * associated with the current argument index that is present, which can be 738dbcf02cSchristos * found in the iterator's @this_arg_index member. This arg index corresponds 748dbcf02cSchristos * to the IEEE80211_RADIOTAP_... defines. 758dbcf02cSchristos * 768dbcf02cSchristos * Radiotap header length: 778dbcf02cSchristos * You can find the CPU-endian total radiotap header length in 788dbcf02cSchristos * iterator->max_length after executing ieee80211_radiotap_iterator_init() 798dbcf02cSchristos * successfully. 808dbcf02cSchristos * 818dbcf02cSchristos * Alignment Gotcha: 828dbcf02cSchristos * You must take care when dereferencing iterator.this_arg 838dbcf02cSchristos * for multibyte types... the pointer is not aligned. Use 848dbcf02cSchristos * get_unaligned((type *)iterator.this_arg) to dereference 858dbcf02cSchristos * iterator.this_arg for type "type" safely on all arches. 868dbcf02cSchristos * 873c260e60Schristos * Example code: parse.c 888dbcf02cSchristos */ 898dbcf02cSchristos 908dbcf02cSchristos int ieee80211_radiotap_iterator_init( 918dbcf02cSchristos struct ieee80211_radiotap_iterator *iterator, 928dbcf02cSchristos struct ieee80211_radiotap_header *radiotap_header, 933c260e60Schristos int max_length, const struct ieee80211_radiotap_vendor_namespaces *vns) 948dbcf02cSchristos { 953c260e60Schristos /* must at least have the radiotap header */ 963c260e60Schristos if (max_length < (int)sizeof(struct ieee80211_radiotap_header)) 973c260e60Schristos return -EINVAL; 983c260e60Schristos 998dbcf02cSchristos /* Linux only supports version 0 radiotap format */ 1008dbcf02cSchristos if (radiotap_header->it_version) 1018dbcf02cSchristos return -EINVAL; 1028dbcf02cSchristos 1038dbcf02cSchristos /* sanity check for allowed length and radiotap length field */ 1043c260e60Schristos if (max_length < get_unaligned_le16(&radiotap_header->it_len)) 1058dbcf02cSchristos return -EINVAL; 1068dbcf02cSchristos 1073c260e60Schristos iterator->_rtheader = radiotap_header; 1083c260e60Schristos iterator->_max_length = get_unaligned_le16(&radiotap_header->it_len); 1093c260e60Schristos iterator->_arg_index = 0; 1103c260e60Schristos iterator->_bitmap_shifter = get_unaligned_le32(&radiotap_header->it_present); 1113c260e60Schristos iterator->_arg = (uint8_t *)radiotap_header + sizeof(*radiotap_header); 112bb610346Schristos iterator->_next_ns_data = NULL; 1133c260e60Schristos iterator->_reset_on_ext = 0; 114*bb618362Schristos iterator->_next_bitmap = (le32 *) (((u8 *) radiotap_header) + offsetof(struct ieee80211_radiotap_header, it_present)); 1153c260e60Schristos iterator->_next_bitmap++; 1163c260e60Schristos iterator->_vns = vns; 1173c260e60Schristos iterator->current_namespace = &radiotap_ns; 1183c260e60Schristos iterator->is_radiotap_ns = 1; 1193c260e60Schristos #ifdef RADIOTAP_SUPPORT_OVERRIDES 1203c260e60Schristos iterator->n_overrides = 0; 1213c260e60Schristos iterator->overrides = NULL; 1223c260e60Schristos #endif 1238dbcf02cSchristos 1248dbcf02cSchristos /* find payload start allowing for extended bitmap(s) */ 1258dbcf02cSchristos 12636ebd06eSchristos if (iterator->_bitmap_shifter & BIT(IEEE80211_RADIOTAP_EXT)) { 1273c260e60Schristos if ((unsigned long)iterator->_arg - 1283c260e60Schristos (unsigned long)iterator->_rtheader + sizeof(uint32_t) > 1293c260e60Schristos (unsigned long)iterator->_max_length) 1303c260e60Schristos return -EINVAL; 1313c260e60Schristos while (get_unaligned_le32(iterator->_arg) & 13236ebd06eSchristos BIT(IEEE80211_RADIOTAP_EXT)) { 1333c260e60Schristos iterator->_arg += sizeof(uint32_t); 1348dbcf02cSchristos 1358dbcf02cSchristos /* 1368dbcf02cSchristos * check for insanity where the present bitmaps 1378dbcf02cSchristos * keep claiming to extend up to or even beyond the 1388dbcf02cSchristos * stated radiotap header length 1398dbcf02cSchristos */ 1408dbcf02cSchristos 1413c260e60Schristos if ((unsigned long)iterator->_arg - 1423c260e60Schristos (unsigned long)iterator->_rtheader + 1433c260e60Schristos sizeof(uint32_t) > 1443c260e60Schristos (unsigned long)iterator->_max_length) 1458dbcf02cSchristos return -EINVAL; 1468dbcf02cSchristos } 1478dbcf02cSchristos 1483c260e60Schristos iterator->_arg += sizeof(uint32_t); 1498dbcf02cSchristos 1508dbcf02cSchristos /* 1518dbcf02cSchristos * no need to check again for blowing past stated radiotap 1528dbcf02cSchristos * header length, because ieee80211_radiotap_iterator_next 1538dbcf02cSchristos * checks it before it is dereferenced 1548dbcf02cSchristos */ 1558dbcf02cSchristos } 1568dbcf02cSchristos 1573c260e60Schristos iterator->this_arg = iterator->_arg; 158bb610346Schristos iterator->this_arg_index = 0; 159bb610346Schristos iterator->this_arg_size = 0; 1603c260e60Schristos 1618dbcf02cSchristos /* we are all initialized happily */ 1628dbcf02cSchristos 1638dbcf02cSchristos return 0; 1648dbcf02cSchristos } 1658dbcf02cSchristos 1663c260e60Schristos static void find_ns(struct ieee80211_radiotap_iterator *iterator, 1673c260e60Schristos uint32_t oui, uint8_t subns) 1683c260e60Schristos { 1693c260e60Schristos int i; 1703c260e60Schristos 1713c260e60Schristos iterator->current_namespace = NULL; 1723c260e60Schristos 1733c260e60Schristos if (!iterator->_vns) 1743c260e60Schristos return; 1753c260e60Schristos 1763c260e60Schristos for (i = 0; i < iterator->_vns->n_ns; i++) { 1773c260e60Schristos if (iterator->_vns->ns[i].oui != oui) 1783c260e60Schristos continue; 1793c260e60Schristos if (iterator->_vns->ns[i].subns != subns) 1803c260e60Schristos continue; 1813c260e60Schristos 1823c260e60Schristos iterator->current_namespace = &iterator->_vns->ns[i]; 1833c260e60Schristos break; 1843c260e60Schristos } 1853c260e60Schristos } 1863c260e60Schristos 1873c260e60Schristos #ifdef RADIOTAP_SUPPORT_OVERRIDES 1883c260e60Schristos static int find_override(struct ieee80211_radiotap_iterator *iterator, 1893c260e60Schristos int *align, int *size) 1903c260e60Schristos { 1913c260e60Schristos int i; 1923c260e60Schristos 1933c260e60Schristos if (!iterator->overrides) 1943c260e60Schristos return 0; 1953c260e60Schristos 1963c260e60Schristos for (i = 0; i < iterator->n_overrides; i++) { 1973c260e60Schristos if (iterator->_arg_index == iterator->overrides[i].field) { 1983c260e60Schristos *align = iterator->overrides[i].align; 1993c260e60Schristos *size = iterator->overrides[i].size; 2003c260e60Schristos if (!*align) /* erroneous override */ 2013c260e60Schristos return 0; 2023c260e60Schristos return 1; 2033c260e60Schristos } 2043c260e60Schristos } 2053c260e60Schristos 2063c260e60Schristos return 0; 2073c260e60Schristos } 2083c260e60Schristos #endif 2093c260e60Schristos 2108dbcf02cSchristos 2118dbcf02cSchristos /** 2128dbcf02cSchristos * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg 2138dbcf02cSchristos * @iterator: radiotap_iterator to move to next arg (if any) 2148dbcf02cSchristos * 2158dbcf02cSchristos * Returns: 0 if there is an argument to handle, 2168dbcf02cSchristos * -ENOENT if there are no more args or -EINVAL 2178dbcf02cSchristos * if there is something else wrong. 2188dbcf02cSchristos * 2198dbcf02cSchristos * This function provides the next radiotap arg index (IEEE80211_RADIOTAP_*) 2208dbcf02cSchristos * in @this_arg_index and sets @this_arg to point to the 2218dbcf02cSchristos * payload for the field. It takes care of alignment handling and extended 2228dbcf02cSchristos * present fields. @this_arg can be changed by the caller (eg, 2238dbcf02cSchristos * incremented to move inside a compound argument like 2248dbcf02cSchristos * IEEE80211_RADIOTAP_CHANNEL). The args pointed to are in 225*bb618362Schristos * little-endian format whatever the endianness of your CPU. 2268dbcf02cSchristos * 2278dbcf02cSchristos * Alignment Gotcha: 2288dbcf02cSchristos * You must take care when dereferencing iterator.this_arg 2298dbcf02cSchristos * for multibyte types... the pointer is not aligned. Use 2308dbcf02cSchristos * get_unaligned((type *)iterator.this_arg) to dereference 2318dbcf02cSchristos * iterator.this_arg for type "type" safely on all arches. 2328dbcf02cSchristos */ 2338dbcf02cSchristos 2348dbcf02cSchristos int ieee80211_radiotap_iterator_next( 2358dbcf02cSchristos struct ieee80211_radiotap_iterator *iterator) 2368dbcf02cSchristos { 2373c260e60Schristos while (1) { 2388dbcf02cSchristos int hit = 0; 2393c260e60Schristos int pad, align, size, subns; 2403c260e60Schristos uint32_t oui; 2418dbcf02cSchristos 2423c260e60Schristos /* if no more EXT bits, that's it */ 2433c260e60Schristos if ((iterator->_arg_index % 32) == IEEE80211_RADIOTAP_EXT && 2443c260e60Schristos !(iterator->_bitmap_shifter & 1)) 2453c260e60Schristos return -ENOENT; 2463c260e60Schristos 2473c260e60Schristos if (!(iterator->_bitmap_shifter & 1)) 2488dbcf02cSchristos goto next_entry; /* arg not present */ 2498dbcf02cSchristos 2503c260e60Schristos /* get alignment/size of data */ 2513c260e60Schristos switch (iterator->_arg_index % 32) { 2523c260e60Schristos case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE: 2533c260e60Schristos case IEEE80211_RADIOTAP_EXT: 2543c260e60Schristos align = 1; 2553c260e60Schristos size = 0; 2563c260e60Schristos break; 2573c260e60Schristos case IEEE80211_RADIOTAP_VENDOR_NAMESPACE: 2583c260e60Schristos align = 2; 2593c260e60Schristos size = 6; 2603c260e60Schristos break; 2613c260e60Schristos default: 2623c260e60Schristos #ifdef RADIOTAP_SUPPORT_OVERRIDES 2633c260e60Schristos if (find_override(iterator, &align, &size)) { 2643c260e60Schristos /* all set */ 2653c260e60Schristos } else 2663c260e60Schristos #endif 2673c260e60Schristos if (!iterator->current_namespace || 2683c260e60Schristos iterator->_arg_index >= iterator->current_namespace->n_bits) { 2693c260e60Schristos if (iterator->current_namespace == &radiotap_ns) 2703c260e60Schristos return -ENOENT; 2713c260e60Schristos align = 0; 2723c260e60Schristos } else { 2733c260e60Schristos align = iterator->current_namespace->align_size[iterator->_arg_index].align; 2743c260e60Schristos size = iterator->current_namespace->align_size[iterator->_arg_index].size; 2753c260e60Schristos } 2763c260e60Schristos if (!align) { 2773c260e60Schristos /* skip all subsequent data */ 2783c260e60Schristos iterator->_arg = iterator->_next_ns_data; 2793c260e60Schristos /* give up on this namespace */ 2803c260e60Schristos iterator->current_namespace = NULL; 2813c260e60Schristos goto next_entry; 2823c260e60Schristos } 2833c260e60Schristos break; 2843c260e60Schristos } 2853c260e60Schristos 2868dbcf02cSchristos /* 2878dbcf02cSchristos * arg is present, account for alignment padding 2888dbcf02cSchristos * 2893c260e60Schristos * Note that these alignments are relative to the start 2903c260e60Schristos * of the radiotap header. There is no guarantee 2918dbcf02cSchristos * that the radiotap header itself is aligned on any 2928dbcf02cSchristos * kind of boundary. 2938dbcf02cSchristos * 2943c260e60Schristos * The above is why get_unaligned() is used to dereference 2953c260e60Schristos * multibyte elements from the radiotap area. 2968dbcf02cSchristos */ 2978dbcf02cSchristos 2983c260e60Schristos pad = ((unsigned long)iterator->_arg - 2993c260e60Schristos (unsigned long)iterator->_rtheader) & (align - 1); 3008dbcf02cSchristos 3018dbcf02cSchristos if (pad) 3023c260e60Schristos iterator->_arg += align - pad; 3033c260e60Schristos 3043c260e60Schristos if (iterator->_arg_index % 32 == IEEE80211_RADIOTAP_VENDOR_NAMESPACE) { 3053c260e60Schristos int vnslen; 3063c260e60Schristos 3073c260e60Schristos if ((unsigned long)iterator->_arg + size - 3083c260e60Schristos (unsigned long)iterator->_rtheader > 3093c260e60Schristos (unsigned long)iterator->_max_length) 3103c260e60Schristos return -EINVAL; 3113c260e60Schristos 3123c260e60Schristos oui = (*iterator->_arg << 16) | 3133c260e60Schristos (*(iterator->_arg + 1) << 8) | 3143c260e60Schristos *(iterator->_arg + 2); 3153c260e60Schristos subns = *(iterator->_arg + 3); 3163c260e60Schristos 3173c260e60Schristos find_ns(iterator, oui, subns); 3183c260e60Schristos 3193c260e60Schristos vnslen = get_unaligned_le16(iterator->_arg + 4); 3203c260e60Schristos iterator->_next_ns_data = iterator->_arg + size + vnslen; 3213c260e60Schristos if (!iterator->current_namespace) 3223c260e60Schristos size += vnslen; 3233c260e60Schristos } 3248dbcf02cSchristos 3258dbcf02cSchristos /* 3268dbcf02cSchristos * this is what we will return to user, but we need to 3278dbcf02cSchristos * move on first so next call has something fresh to test 3288dbcf02cSchristos */ 3293c260e60Schristos iterator->this_arg_index = iterator->_arg_index; 3303c260e60Schristos iterator->this_arg = iterator->_arg; 3313c260e60Schristos iterator->this_arg_size = size; 3328dbcf02cSchristos 3338dbcf02cSchristos /* internally move on the size of this arg */ 3343c260e60Schristos iterator->_arg += size; 3358dbcf02cSchristos 3368dbcf02cSchristos /* 3378dbcf02cSchristos * check for insanity where we are given a bitmap that 3388dbcf02cSchristos * claims to have more arg content than the length of the 3398dbcf02cSchristos * radiotap section. We will normally end up equalling this 3408dbcf02cSchristos * max_length on the last arg, never exceeding it. 3418dbcf02cSchristos */ 3428dbcf02cSchristos 3433c260e60Schristos if ((unsigned long)iterator->_arg - 3443c260e60Schristos (unsigned long)iterator->_rtheader > 3453c260e60Schristos (unsigned long)iterator->_max_length) 3468dbcf02cSchristos return -EINVAL; 3478dbcf02cSchristos 3483c260e60Schristos /* these special ones are valid in each bitmap word */ 3493c260e60Schristos switch (iterator->_arg_index % 32) { 3503c260e60Schristos case IEEE80211_RADIOTAP_VENDOR_NAMESPACE: 3513c260e60Schristos iterator->_reset_on_ext = 1; 3523c260e60Schristos 3533c260e60Schristos iterator->is_radiotap_ns = 0; 3543c260e60Schristos /* 3553c260e60Schristos * If parser didn't register this vendor 3563c260e60Schristos * namespace with us, allow it to show it 3573c260e60Schristos * as 'raw. Do do that, set argument index 3583c260e60Schristos * to vendor namespace. 3593c260e60Schristos */ 3603c260e60Schristos iterator->this_arg_index = 3613c260e60Schristos IEEE80211_RADIOTAP_VENDOR_NAMESPACE; 3623c260e60Schristos if (!iterator->current_namespace) 3633c260e60Schristos hit = 1; 3643c260e60Schristos goto next_entry; 3653c260e60Schristos case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE: 3663c260e60Schristos iterator->_reset_on_ext = 1; 3673c260e60Schristos iterator->current_namespace = &radiotap_ns; 3683c260e60Schristos iterator->is_radiotap_ns = 1; 3693c260e60Schristos goto next_entry; 3703c260e60Schristos case IEEE80211_RADIOTAP_EXT: 3713c260e60Schristos /* 3723c260e60Schristos * bit 31 was set, there is more 3733c260e60Schristos * -- move to next u32 bitmap 3743c260e60Schristos */ 3753c260e60Schristos iterator->_bitmap_shifter = 3763c260e60Schristos get_unaligned_le32(iterator->_next_bitmap); 3773c260e60Schristos iterator->_next_bitmap++; 3783c260e60Schristos if (iterator->_reset_on_ext) 3793c260e60Schristos iterator->_arg_index = 0; 3803c260e60Schristos else 3813c260e60Schristos iterator->_arg_index++; 3823c260e60Schristos iterator->_reset_on_ext = 0; 3833c260e60Schristos break; 3843c260e60Schristos default: 3853c260e60Schristos /* we've got a hit! */ 3863c260e60Schristos hit = 1; 3878dbcf02cSchristos next_entry: 3883c260e60Schristos iterator->_bitmap_shifter >>= 1; 3893c260e60Schristos iterator->_arg_index++; 3903c260e60Schristos } 3918dbcf02cSchristos 3928dbcf02cSchristos /* if we found a valid arg earlier, return it now */ 3938dbcf02cSchristos if (hit) 3948dbcf02cSchristos return 0; 3958dbcf02cSchristos } 3968dbcf02cSchristos } 397