xref: /netbsd-src/external/bsd/wpa/dist/src/utils/radiotap.c (revision bb6183629cf165db498d8e1f4e2de129f7efb21c)
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