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