* [PATCH Try#14 1/4] mac80211: Monitor mode radiotap injection docs
2007-06-24 8:57 [PATCH Try#14 0/4] Radiotap injection for any Mode andy
@ 2007-06-24 8:57 ` andy
2007-06-24 9:36 ` Johannes Berg
2007-06-24 8:57 ` [PATCH Try#14 2/4] cfg80211: Radiotap parser andy
` (2 subsequent siblings)
3 siblings, 1 reply; 8+ messages in thread
From: andy @ 2007-06-24 8:57 UTC (permalink / raw)
To: linux-wireless; +Cc: John Linville, Johannes Berg, Jiri Benc, Andy Green
Try #14
- Documented Jiri Benc's injection encapsulation method
Try #lucky13
- Johannes Berg's suggested use of get_unaligned() to protect unaligned
defreferences of all multibyte radiotap stuff
CC: John Linville <linville@tuxdriver.com>
CC: Johannes Berg <johannes@sipsolutions.net>
CC: Jiri Benc <jbenc@suse.cz>
Signed-off-by: Andy Green <andy@warmcat.com>
---
Documentation/networking/mac80211-injection.txt | 88 ++++++++++++++++++++++++
Documentation/networking/radiotap-headers.txt | 87 +++++++++++++++++++++++
2 files changed, 175 insertions(+)
Index: wireless-dev/Documentation/networking/mac80211-injection.txt
===================================================================
--- /dev/null
+++ wireless-dev/Documentation/networking/mac80211-injection.txt
@@ -0,0 +1,88 @@
+How to use packet injection with mac80211
+=========================================
+
+mac80211 now allows arbitrary packets to be injected down any interface from
+userland. The packet you inject needs to be composed in the following format:
+
+ [ encapsulating ethhdr ]
+ [ radiotap header ]
+ [ ieee80211 header ]
+ [ payload ]
+
+The interface can be in any ieee80211 mode (Managed, Monitor), but currently
+Managed mode rejects packets before mac80211 if the interface is not
+associated. Monitor Mode interfaces accept packets for injection even when
+no other interface on the device is associated though.
+
+Encapsulating ethhdr
+--------------------
+
+First the encapsulating ethernet header is a simple fixed struct ethhdr:
+
+ 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX // dest eth addr (ignored)
+ 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX // source eth addr (ignored)
+ 0x00, 0x1B
+
+(The dest and src addr are ignored by the injection code, but the kernel
+networking code can be interested in them for eg, bridging, recommended values
+are TBD).
+
+Radiotap Header
+---------------
+
+The radiotap format is discussed in
+./Documentation/networking/radiotap-headers.txt.
+
+Despite 13 radiotap argument types are currently defined, most only make sense
+to appear on received packets. Currently three kinds of argument are used by
+the injection code, although it knows to skip any other arguments that are
+present (facilitating replay of captured radiotap headers directly):
+
+ - IEEE80211_RADIOTAP_RATE - u8 arg in 500kbps units (0x02 --> 1Mbps)
+
+ - IEEE80211_RADIOTAP_ANTENNA - u8 arg, 0x00 = ant1, 0x01 = ant2
+
+ - IEEE80211_RADIOTAP_DBM_TX_POWER - u8 arg, dBm
+
+Here is an example valid radiotap header defining these three parameters
+
+ 0x00, 0x00, // <-- radiotap version
+ 0x0b, 0x00, // <- radiotap header length
+ 0x04, 0x0c, 0x00, 0x00, // <-- bitmap
+ 0x6c, // <-- rate
+ 0x0c, //<-- tx power
+ 0x01 //<-- antenna
+
+
+ieee80211 header
+----------------
+
+The ieee80211 header follows immediately afterwards, looking for example like
+this:
+
+ 0x08, 0x01, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x13, 0x22, 0x33, 0x44, 0x55, 0x66,
+ 0x13, 0x22, 0x33, 0x44, 0x55, 0x66,
+ 0x10, 0x86
+
+Then lastly there is the payload.
+
+
+Delivering the packet from usermode
+-----------------------------------
+
+After composing the packet contents, it is sent by send()-ing it to a logical
+mac80211 interface that is in Monitor mode. Libpcap can also be used,
+(which is easier than doing the work to bind the socket to the right
+interface), along the following lines:
+
+ ppcap = pcap_open_live(szInterfaceName, 800, 1, 20, szErrbuf);
+...
+ r = pcap_inject(ppcap, u8aSendBuffer, nLength);
+
+You can also find sources for a complete inject test applet here:
+
+http://penumbra.warmcat.com/_twk/tiki-index.php?page=packetspammer
+
+Andy Green <andy@warmcat.com>
Index: wireless-dev/Documentation/networking/radiotap-headers.txt
===================================================================
--- /dev/null
+++ wireless-dev/Documentation/networking/radiotap-headers.txt
@@ -0,0 +1,87 @@
+How to use radiotap headers
+===========================
+
+Pointer to the radiotap include file
+------------------------------------
+
+Radiotap headers are variable-length and extensible, you can get most of the
+information you need to know on them from:
+
+./include/net/ieee80211_radiotap.h
+
+This document gives an overview and warns on some corner cases.
+
+
+Structure of the header
+-----------------------
+
+There is a fixed portion at the start which contains a u32 bitmap that defines
+if the possible argument associated with that bit is present or not. So if b0
+of the it_present member of ieee80211_radiotap_header is set, it means that
+the header for argument index 0 (IEEE80211_RADIOTAP_TSFT) is present in the
+argument area.
+
+ < 8-byte ieee80211_radiotap_header >
+ [ <possible argument bitmap extensions ... > ]
+ [ <argument> ... ]
+
+At the moment there are only 13 possible argument indexes defined, but in case
+we run out of space in the u32 it_present member, it is defined that b31 set
+indicates that there is another u32 bitmap following (shown as "possible
+argument bitmap extensions..." above), and the start of the arguments is moved
+forward 4 bytes each time.
+
+Note also that the it_len member __le16 is set to the total number of bytes
+covered by the ieee80211_radiotap_header and any arguments following.
+
+
+Requirements for arguments
+--------------------------
+
+After the fixed part of the header, the arguments follow for each argument
+index whose matching bit is set in the it_present member of
+ieee80211_radiotap_header.
+
+ - the arguments are all stored little-endian!
+
+ - the argument payload for a given argument index has a fixed size. So
+ IEEE80211_RADIOTAP_TSFT being present always indicates an 8-byte argument is
+ present. See the comments in ./include/net/ieee80211_radiotap.h for a nice
+ breakdown of all the argument sizes
+
+ - the arguments must be aligned to a boundary of the argument size using
+ padding. So a u16 argument must start on the next u16 boundary if it isn't
+ already on one, a u32 must start on the next u32 boundary and so on.
+
+ - "alignment" is relative to the start of the ieee80211_radiotap_header, ie,
+ the first byte of the radiotap header. The absolute alignment of that first
+ byte isn't defined. So even if the whole radiotap header is starting at, eg,
+ address 0x00000003, still the first byte of the radiotap header is treated as
+ 0 for alignment purposes.
+
+ - the above point that there may be no absolute alignment for multibyte
+ entities in the fixed radiotap header or the argument region means that you
+ have to take special evasive action when trying to access these multibyte
+ entities. Some arches like Blackfin cannot deal with an attempt to
+ dereference, eg, a u16 pointer that is pointing to an odd address. Instead
+ you have to use a kernel API get_unaligned() to dereference the pointer,
+ which will do it bytewise on the arches that require that.
+
+ - The arguments for a given argument index can be a compound of multiple types
+ together. For example IEEE80211_RADIOTAP_CHANNEL has an argument payload
+ consisting of two u16s of total length 4. When this happens, the padding
+ rule is applied dealing with a u16, NOT dealing with a 4-byte single entity.
+
+
+Example valid radiotap header
+-----------------------------
+
+ 0x00, 0x00, // <-- radiotap version + pad byte
+ 0x0b, 0x00, // <- radiotap header length
+ 0x04, 0x0c, 0x00, 0x00, // <-- bitmap
+ 0x6c, // <-- rate (in 500kHz units)
+ 0x0c, //<-- tx power
+ 0x01 //<-- antenna
+
+
+Andy Green <andy@warmcat.com>
--
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [PATCH Try#14 1/4] mac80211: Monitor mode radiotap injection docs
2007-06-24 8:57 ` [PATCH Try#14 1/4] mac80211: Monitor mode radiotap injection docs andy
@ 2007-06-24 9:36 ` Johannes Berg
2007-06-24 10:51 ` Jiri Benc
0 siblings, 1 reply; 8+ messages in thread
From: Johannes Berg @ 2007-06-24 9:36 UTC (permalink / raw)
To: andy; +Cc: linux-wireless, John Linville, Jiri Benc
[-- Attachment #1: Type: text/plain, Size: 421 bytes --]
On Sun, 2007-06-24 at 09:57 +0100, andy@warmcat.com wrote:
> plain text document attachment (mac80211-docs-radiotap-usage.patch)
> Try #14
> - Documented Jiri Benc's injection encapsulation method
I still don't see the point since we've previously established that it
won't help on other interfaces (qdiscs, ...); for monitor interfaces #13
is enough and much simpler.
I'd vote for applying #13.
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 190 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH Try#14 1/4] mac80211: Monitor mode radiotap injection docs
2007-06-24 9:36 ` Johannes Berg
@ 2007-06-24 10:51 ` Jiri Benc
2007-06-24 16:16 ` Andy Green
0 siblings, 1 reply; 8+ messages in thread
From: Jiri Benc @ 2007-06-24 10:51 UTC (permalink / raw)
To: Johannes Berg; +Cc: andy, linux-wireless, John Linville
On Sun, 24 Jun 2007 11:36:32 +0200, Johannes Berg wrote:
> On Sun, 2007-06-24 at 09:57 +0100, andy@warmcat.com wrote:
> > plain text document attachment (mac80211-docs-radiotap-usage.patch)
> > Try #14
> > - Documented Jiri Benc's injection encapsulation method
Hm, replied to the other (kill mgmt interface) thread without looking
through other mails :-(
> I still don't see the point since we've previously established that it
> won't help on other interfaces (qdiscs, ...); for monitor interfaces #13
> is enough and much simpler.
>
> I'd vote for applying #13.
Agreed.
Jiri
--
Jiri Benc
SUSE Labs
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH Try#14 1/4] mac80211: Monitor mode radiotap injection docs
2007-06-24 10:51 ` Jiri Benc
@ 2007-06-24 16:16 ` Andy Green
0 siblings, 0 replies; 8+ messages in thread
From: Andy Green @ 2007-06-24 16:16 UTC (permalink / raw)
To: Jiri Benc; +Cc: Johannes Berg, linux-wireless, John Linville
Jiri Benc wrote:
> On Sun, 24 Jun 2007 11:36:32 +0200, Johannes Berg wrote:
>> On Sun, 2007-06-24 at 09:57 +0100, andy@warmcat.com wrote:
>>> plain text document attachment (mac80211-docs-radiotap-usage.patch)
>>> Try #14
>>> - Documented Jiri Benc's injection encapsulation method
>
> Hm, replied to the other (kill mgmt interface) thread without looking
> through other mails :-(
>
>> I still don't see the point since we've previously established that it
>> won't help on other interfaces (qdiscs, ...); for monitor interfaces #13
>> is enough and much simpler.
>>
>> I'd vote for applying #13.
>
> Agreed.
Great, well let's go with that.
-Andy
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH Try#14 2/4] cfg80211: Radiotap parser
2007-06-24 8:57 [PATCH Try#14 0/4] Radiotap injection for any Mode andy
2007-06-24 8:57 ` [PATCH Try#14 1/4] mac80211: Monitor mode radiotap injection docs andy
@ 2007-06-24 8:57 ` andy
2007-06-24 8:58 ` [PATCH Try#14 3/4] --- include/linux/if_ether.h | 1 + 1 file changed, 1 insertion(+) andy
2007-06-24 8:58 ` [PATCH Try#14 4/4] mac80211: Monitor mode radiotap-based packet injection andy
3 siblings, 0 replies; 8+ messages in thread
From: andy @ 2007-06-24 8:57 UTC (permalink / raw)
To: linux-wireless; +Cc: John Linville, Johannes Berg, Jiri Benc, Andy Green
Generic code to walk through the fields in a radiotap header, accounting
for nasties like extended "field present" bitfields and alignment rules
Try #lucky13
- Integrated a patch from Michael Wu with (Thanks again Michael)
- whitespace errors
- an endian error
- a strict endian typing problem
- Johannes Berg's suggested use of get_unaligned() to protect unaligned
defreferences of all multibyte radiotap stuff
Try #12 comments from Michael Wu
- Use 1<<IEEE80211_RADIOTAP_EXT then no need to add mask to radiotap hdr
- Revert Johannes' enum method
- break down padding action with temp var
Try #11
- parser returns enum retcode - Johannes Berg
Try #10 comments from Michael Wu
- kill some spaces between * and var/arg
- weed out cut-n-pasted #includes that aren't actually used
- kill vertical justification
- kill unneccessary parenthesis in some expressions
- sizeof() on dereferenced vars not types
- ulong pointer arithmetic! Good catch!
Try #9 (of the radiotap patchset) thanks to Johannes Berg's feedback
- Add docs to nano kernel docs
- Add docs to Documentation/networking/radiotap-headers.txt
- Fix typos
Try #2
- added sanity check to extended present bitmap u32 walking code - disallow
possibility to walk past the end of the radiotap header length
Try #1
- Based on Johannes Berg's comments, broke out the radiotap parsing into
its own file as part of cfg80211
- From same comments, added mask constant for b31 of arg presence bitfield
to ieee80211_radiotap.h
- Fixed subtle but nasty bug with alignment: args in the radiotap area are
aligned *relative to the start of the header* now. The header is not
guaranteed to align to anything (it is randomly in an skb data area).
CC: John Linville <linville@tuxdriver.com>
CC: Johannes Berg <johannes@sipsolutions.net>
CC: Jiri Benc <jbenc@suse.cz>
Signed-off-by: Andy Green <andy@warmcat.com>
===================================================
---
Documentation/networking/radiotap-headers.txt | 65 ++++++
include/net/cfg80211.h | 38 +++
net/wireless/Makefile | 2
net/wireless/radiotap.c | 257 ++++++++++++++++++++++++++
4 files changed, 361 insertions(+), 1 deletion(-)
Index: wireless-dev/include/net/cfg80211.h
===================================================================
--- wireless-dev.orig/include/net/cfg80211.h
+++ wireless-dev/include/net/cfg80211.h
@@ -75,6 +75,44 @@ struct key_params {
u32 cipher;
};
+
+/* Radiotap header iteration
+ * implemented in net/wireless/radiotap.c
+ * docs in Documentation/networking/radiotap-headers.txt
+ */
+/**
+ * struct ieee80211_radiotap_iterator - tracks walk thru present radiotap args
+ * @rtheader: pointer to the radiotap header we are walking through
+ * @max_length: length of radiotap header in cpu byte ordering
+ * @this_arg_index: IEEE80211_RADIOTAP_... index of current arg
+ * @this_arg: pointer to current radiotap arg
+ * @arg_index: internal next argument index
+ * @arg: internal next argument pointer
+ * @next_bitmap: internal pointer to next present u32
+ * @bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present
+ */
+
+struct ieee80211_radiotap_iterator {
+ struct ieee80211_radiotap_header *rtheader;
+ int max_length;
+ int this_arg_index;
+ u8 *this_arg;
+
+ int arg_index;
+ u8 *arg;
+ __le32 *next_bitmap;
+ u32 bitmap_shifter;
+};
+
+extern int ieee80211_radiotap_iterator_init(
+ struct ieee80211_radiotap_iterator *iterator,
+ struct ieee80211_radiotap_header *radiotap_header,
+ int max_length);
+
+extern int ieee80211_radiotap_iterator_next(
+ struct ieee80211_radiotap_iterator *iterator);
+
+
/* from net/wireless.h */
struct wiphy;
Index: wireless-dev/net/wireless/Makefile
===================================================================
--- wireless-dev.orig/net/wireless/Makefile
+++ wireless-dev/net/wireless/Makefile
@@ -1,5 +1,5 @@
obj-$(CONFIG_WIRELESS_EXT) += wext.o
obj-$(CONFIG_CFG80211) += cfg80211.o
-cfg80211-y += core.o sysfs.o
+cfg80211-y += core.o sysfs.o radiotap.o
cfg80211-$(CONFIG_NL80211) += nl80211.o
Index: wireless-dev/net/wireless/radiotap.c
===================================================================
--- /dev/null
+++ wireless-dev/net/wireless/radiotap.c
@@ -0,0 +1,257 @@
+/*
+ * Radiotap parser
+ *
+ * Copyright 2007 Andy Green <andy@warmcat.com>
+ */
+
+#include <net/cfg80211.h>
+#include <net/ieee80211_radiotap.h>
+#include <asm/unaligned.h>
+
+/* function prototypes and related defs are in include/net/cfg80211.h */
+
+/**
+ * ieee80211_radiotap_iterator_init - radiotap parser iterator initialization
+ * @iterator: radiotap_iterator to initialize
+ * @radiotap_header: radiotap header to parse
+ * @max_length: total length we can parse into (eg, whole packet length)
+ *
+ * Returns: 0 or a negative error code if there is a problem.
+ *
+ * This function initializes an opaque iterator struct which can then
+ * be passed to ieee80211_radiotap_iterator_next() to visit every radiotap
+ * argument which is present in the header. It knows about extended
+ * present headers and handles them.
+ *
+ * How to use:
+ * call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator
+ * struct ieee80211_radiotap_iterator (no need to init the struct beforehand)
+ * checking for a good 0 return code. Then loop calling
+ * __ieee80211_radiotap_iterator_next()... it returns either 0,
+ * -ENOENT if there are no more args to parse, or -EINVAL if there is a problem.
+ * The iterator's @this_arg member points to the start of the argument
+ * associated with the current argument index that is present, which can be
+ * found in the iterator's @this_arg_index member. This arg index corresponds
+ * to the IEEE80211_RADIOTAP_... defines.
+ *
+ * Radiotap header length:
+ * You can find the CPU-endian total radiotap header length in
+ * iterator->max_length after executing ieee80211_radiotap_iterator_init()
+ * successfully.
+ *
+ * Alignment Gotcha:
+ * You must take care when dereferencing iterator.this_arg
+ * for multibyte types... the pointer is not aligned. Use
+ * get_unaligned((type *)iterator.this_arg) to dereference
+ * iterator.this_arg for type "type" safely on all arches.
+ *
+ * Example code:
+ * See Documentation/networking/radiotap-headers.txt
+ */
+
+int ieee80211_radiotap_iterator_init(
+ struct ieee80211_radiotap_iterator *iterator,
+ struct ieee80211_radiotap_header *radiotap_header,
+ int max_length)
+{
+ /* Linux only supports version 0 radiotap format */
+ if (radiotap_header->it_version)
+ return -EINVAL;
+
+ /* sanity check for allowed length and radiotap length field */
+ if (max_length < le16_to_cpu(get_unaligned(&radiotap_header->it_len)))
+ return -EINVAL;
+
+ iterator->rtheader = radiotap_header;
+ iterator->max_length = le16_to_cpu(get_unaligned(
+ &radiotap_header->it_len));
+ iterator->arg_index = 0;
+ iterator->bitmap_shifter = le32_to_cpu(get_unaligned(
+ &radiotap_header->it_present));
+ iterator->arg = (u8 *)radiotap_header + sizeof(*radiotap_header);
+ iterator->this_arg = NULL;
+
+ /* find payload start allowing for extended bitmap(s) */
+
+ if (unlikely(iterator->bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT))) {
+ while (le32_to_cpu(get_unaligned((__le32 *)iterator->arg)) &
+ (1<<IEEE80211_RADIOTAP_EXT)) {
+ iterator->arg += sizeof(u32);
+
+ /*
+ * check for insanity where the present bitmaps
+ * keep claiming to extend up to or even beyond the
+ * stated radiotap header length
+ */
+
+ if (((ulong)iterator->arg -
+ (ulong)iterator->rtheader) > iterator->max_length)
+ return -EINVAL;
+ }
+
+ iterator->arg += sizeof(u32);
+
+ /*
+ * no need to check again for blowing past stated radiotap
+ * header length, because ieee80211_radiotap_iterator_next
+ * checks it before it is dereferenced
+ */
+ }
+
+ /* we are all initialized happily */
+
+ return 0;
+}
+EXPORT_SYMBOL(ieee80211_radiotap_iterator_init);
+
+
+/**
+ * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg
+ * @iterator: radiotap_iterator to move to next arg (if any)
+ *
+ * Returns: 0 if there is an argument to handle,
+ * -ENOENT if there are no more args or -EINVAL
+ * if there is something else wrong.
+ *
+ * This function provides the next radiotap arg index (IEEE80211_RADIOTAP_*)
+ * in @this_arg_index and sets @this_arg to point to the
+ * payload for the field. It takes care of alignment handling and extended
+ * present fields. @this_arg can be changed by the caller (eg,
+ * incremented to move inside a compound argument like
+ * IEEE80211_RADIOTAP_CHANNEL). The args pointed to are in
+ * little-endian format whatever the endianess of your CPU.
+ *
+ * Alignment Gotcha:
+ * You must take care when dereferencing iterator.this_arg
+ * for multibyte types... the pointer is not aligned. Use
+ * get_unaligned((type *)iterator.this_arg) to dereference
+ * iterator.this_arg for type "type" safely on all arches.
+ */
+
+int ieee80211_radiotap_iterator_next(
+ struct ieee80211_radiotap_iterator *iterator)
+{
+
+ /*
+ * small length lookup table for all radiotap types we heard of
+ * starting from b0 in the bitmap, so we can walk the payload
+ * area of the radiotap header
+ *
+ * There is a requirement to pad args, so that args
+ * of a given length must begin at a boundary of that length
+ * -- but note that compound args are allowed (eg, 2 x u16
+ * for IEEE80211_RADIOTAP_CHANNEL) so total arg length is not
+ * a reliable indicator of alignment requirement.
+ *
+ * upper nybble: content alignment for arg
+ * lower nybble: content length for arg
+ */
+
+ static const u8 rt_sizes[] = {
+ [IEEE80211_RADIOTAP_TSFT] = 0x88,
+ [IEEE80211_RADIOTAP_FLAGS] = 0x11,
+ [IEEE80211_RADIOTAP_RATE] = 0x11,
+ [IEEE80211_RADIOTAP_CHANNEL] = 0x24,
+ [IEEE80211_RADIOTAP_FHSS] = 0x22,
+ [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = 0x11,
+ [IEEE80211_RADIOTAP_DBM_ANTNOISE] = 0x11,
+ [IEEE80211_RADIOTAP_LOCK_QUALITY] = 0x22,
+ [IEEE80211_RADIOTAP_TX_ATTENUATION] = 0x22,
+ [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = 0x22,
+ [IEEE80211_RADIOTAP_DBM_TX_POWER] = 0x11,
+ [IEEE80211_RADIOTAP_ANTENNA] = 0x11,
+ [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = 0x11,
+ [IEEE80211_RADIOTAP_DB_ANTNOISE] = 0x11
+ /*
+ * add more here as they are defined in
+ * include/net/ieee80211_radiotap.h
+ */
+ };
+
+ /*
+ * for every radiotap entry we can at
+ * least skip (by knowing the length)...
+ */
+
+ while (iterator->arg_index < sizeof(rt_sizes)) {
+ int hit = 0;
+ int pad;
+
+ if (!(iterator->bitmap_shifter & 1))
+ goto next_entry; /* arg not present */
+
+ /*
+ * arg is present, account for alignment padding
+ * 8-bit args can be at any alignment
+ * 16-bit args must start on 16-bit boundary
+ * 32-bit args must start on 32-bit boundary
+ * 64-bit args must start on 64-bit boundary
+ *
+ * note that total arg size can differ from alignment of
+ * elements inside arg, so we use upper nybble of length
+ * table to base alignment on
+ *
+ * also note: these alignments are ** relative to the
+ * start of the radiotap header **. There is no guarantee
+ * that the radiotap header itself is aligned on any
+ * kind of boundary.
+ *
+ * the above is why get_unaligned() is used to dereference
+ * multibyte elements from the radiotap area
+ */
+
+ pad = (((ulong)iterator->arg) -
+ ((ulong)iterator->rtheader)) &
+ ((rt_sizes[iterator->arg_index] >> 4) - 1);
+
+ if (pad)
+ iterator->arg +=
+ (rt_sizes[iterator->arg_index] >> 4) - pad;
+
+ /*
+ * this is what we will return to user, but we need to
+ * move on first so next call has something fresh to test
+ */
+ iterator->this_arg_index = iterator->arg_index;
+ iterator->this_arg = iterator->arg;
+ hit = 1;
+
+ /* internally move on the size of this arg */
+ iterator->arg += rt_sizes[iterator->arg_index] & 0x0f;
+
+ /*
+ * check for insanity where we are given a bitmap that
+ * claims to have more arg content than the length of the
+ * radiotap section. We will normally end up equalling this
+ * max_length on the last arg, never exceeding it.
+ */
+
+ if (((ulong)iterator->arg - (ulong)iterator->rtheader) >
+ iterator->max_length)
+ return -EINVAL;
+
+ next_entry:
+ iterator->arg_index++;
+ if (unlikely((iterator->arg_index & 31) == 0)) {
+ /* completed current u32 bitmap */
+ if (iterator->bitmap_shifter & 1) {
+ /* b31 was set, there is more */
+ /* move to next u32 bitmap */
+ iterator->bitmap_shifter = le32_to_cpu(
+ get_unaligned(iterator->next_bitmap));
+ iterator->next_bitmap++;
+ } else
+ /* no more bitmaps: end */
+ iterator->arg_index = sizeof(rt_sizes);
+ } else /* just try the next bit */
+ iterator->bitmap_shifter >>= 1;
+
+ /* if we found a valid arg earlier, return it now */
+ if (hit)
+ return 0;
+ }
+
+ /* we don't know how to handle any more args, we're done */
+ return -ENOENT;
+}
+EXPORT_SYMBOL(ieee80211_radiotap_iterator_next);
Index: wireless-dev/Documentation/networking/radiotap-headers.txt
===================================================================
--- wireless-dev.orig/Documentation/networking/radiotap-headers.txt
+++ wireless-dev/Documentation/networking/radiotap-headers.txt
@@ -84,4 +84,69 @@ Example valid radiotap header
0x01 //<-- antenna
+Using the Radiotap Parser
+-------------------------
+
+If you are having to parse a radiotap struct, you can radically simplify the
+job by using the radiotap parser that lives in net/wireless/radiotap.c and has
+its prototypes available in include/net/cfg80211.h. You use it like this:
+
+#include <net/cfg80211.h>
+
+/* buf points to the start of the radiotap header part */
+
+int MyFunction(u8 * buf, int buflen)
+{
+ int pkt_rate_100kHz = 0, antenna = 0, pwr = 0;
+ struct ieee80211_radiotap_iterator iterator;
+ int ret = ieee80211_radiotap_iterator_init(&iterator, buf, buflen);
+
+ while (!ret) {
+
+ ret = ieee80211_radiotap_iterator_next(&iterator);
+
+ if (ret)
+ continue;
+
+ /* see if this argument is something we can use */
+
+ switch (iterator.this_arg_index) {
+ /*
+ * You must take care when dereferencing iterator.this_arg
+ * for multibyte types... the pointer is not aligned. Use
+ * get_unaligned((type *)iterator.this_arg) to dereference
+ * iterator.this_arg for type "type" safely on all arches.
+ */
+ case IEEE80211_RADIOTAP_RATE:
+ /* radiotap "rate" u8 is in
+ * 500kbps units, eg, 0x02=1Mbps
+ */
+ pkt_rate_100kHz = (*iterator.this_arg) * 5;
+ break;
+
+ case IEEE80211_RADIOTAP_ANTENNA:
+ /* radiotap uses 0 for 1st ant */
+ antenna = *iterator.this_arg);
+ break;
+
+ case IEEE80211_RADIOTAP_DBM_TX_POWER:
+ pwr = *iterator.this_arg;
+ break;
+
+ default:
+ break;
+ }
+ } /* while more rt headers */
+
+ if (ret != -ENOENT)
+ return TXRX_DROP;
+
+ /* discard the radiotap header part */
+ buf += iterator.max_length;
+ buflen -= iterator.max_length;
+
+ ...
+
+}
+
Andy Green <andy@warmcat.com>
--
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH Try#14 3/4] --- include/linux/if_ether.h | 1 + 1 file changed, 1 insertion(+)
2007-06-24 8:57 [PATCH Try#14 0/4] Radiotap injection for any Mode andy
2007-06-24 8:57 ` [PATCH Try#14 1/4] mac80211: Monitor mode radiotap injection docs andy
2007-06-24 8:57 ` [PATCH Try#14 2/4] cfg80211: Radiotap parser andy
@ 2007-06-24 8:58 ` andy
2007-06-24 8:58 ` [PATCH Try#14 4/4] mac80211: Monitor mode radiotap-based packet injection andy
3 siblings, 0 replies; 8+ messages in thread
From: andy @ 2007-06-24 8:58 UTC (permalink / raw)
To: linux-wireless
Index: wireless-dev/include/linux/if_ether.h
===================================================================
--- wireless-dev.orig/include/linux/if_ether.h
+++ wireless-dev/include/linux/if_ether.h
@@ -98,6 +98,7 @@
#define ETH_P_ECONET 0x0018 /* Acorn Econet */
#define ETH_P_HDLC 0x0019 /* HDLC frames */
#define ETH_P_ARCNET 0x001A /* 1A for ArcNet :-) */
+#define ETH_P_80211_RT 0x001B /* Radiotap + 80211 encapsulation */
/*
* This is an Ethernet frame header.
--
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH Try#14 4/4] mac80211: Monitor mode radiotap-based packet injection
2007-06-24 8:57 [PATCH Try#14 0/4] Radiotap injection for any Mode andy
` (2 preceding siblings ...)
2007-06-24 8:58 ` [PATCH Try#14 3/4] --- include/linux/if_ether.h | 1 + 1 file changed, 1 insertion(+) andy
@ 2007-06-24 8:58 ` andy
3 siblings, 0 replies; 8+ messages in thread
From: andy @ 2007-06-24 8:58 UTC (permalink / raw)
To: linux-wireless; +Cc: John Linville, Johannes Berg, Jiri Benc, Andy Green
Try #14
- Changed to Jiri Benc's injection encapsulation method
Try #Lucky13
- Integrated a patch from Michael Wu with (Thanks again Michael)
- whitespace errors
- an endian error
- a strict endian typing problem
- Johannes Berg's suggested use of get_unaligned() to protect unaligned
defreferences of all multibyte radiotap stuff
Try #12 Comments from Michael Wu
- Revert enum retcode stuff
- Handle flags, checking if FCS marked as present and snipping it
- kill a blank line
Try #11
- Change parser loop code around to deal with enum retcodes
Try #10 Comments from Michael Wu
- __ieee80211_convert_radiotap_to_control_and_remove ->
__ieee80211_parse_tx_radiotap
- death to vertical justification
- -ve to negative
- struct ieee80211_hw_mode should be called "mode" by convention
Try #9
- Normalize multiline comment style
Try #6
- Accounted for various comments from Johannes Berg
- Radiotap parsing is moved to cfg80211 as requested in a separate patch
Try #5
- De-indent last few indented comments
Try #4
- All from Michael Wu's feedback: further style heresies removed
- took account of radiotap arg alignment requirement. n-byte arg must be
placed on n-byte boundary using padding where necessary
Try #3
- moved to Michael Wu's method of tracking if we came in on a
monitor interface by using ifindex
- removed older proposed monitor interface tracking method and flags
- style fixes
- removed duped #include that is present in Michael Wu's patch already
Try #2
- took Michael Wu's advice about better tools and basing on wireless-dev
- took Luis Rodriguez's advice about coding style makeover
- took Pavel Roskin's advice about little-endian radiotap
CC: John Linville <linville@tuxdriver.com>
CC: Johannes Berg <johannes@sipsolutions.net>
CC: Jiri Benc <jbenc@suse.cz>
Signed-off-by: Andy Green <andy@warmcat.com>
---
net/mac80211/ieee80211.c | 283 +++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 273 insertions(+), 10 deletions(-)
Index: wireless-dev/net/mac80211/ieee80211.c
===================================================================
--- wireless-dev.orig/net/mac80211/ieee80211.c
+++ wireless-dev/net/mac80211/ieee80211.c
@@ -24,6 +24,7 @@
#include <linux/compiler.h>
#include <linux/bitmap.h>
#include <net/cfg80211.h>
+#include <asm/unaligned.h>
#include "ieee80211_common.h"
#include "ieee80211_i.h"
@@ -1118,7 +1119,135 @@ ieee80211_tx_h_ps_buf(struct ieee80211_t
}
-static void inline
+/*
+ * deal with packet injection down monitor interface
+ * with Radiotap Header -- only called for monitor mode interface
+ */
+
+static ieee80211_txrx_result
+__ieee80211_parse_tx_radiotap(
+ struct ieee80211_txrx_data *tx,
+ struct sk_buff *skb, struct ieee80211_tx_control *control)
+{
+ /*
+ * this is the moment to interpret and discard the radiotap header that
+ * must be at the start of the packet injected in Monitor mode
+ *
+ * Need to take some care with endian-ness, since radiotap
+ * args are always little-endian
+ */
+ struct ieee80211_radiotap_iterator iterator;
+ struct ieee80211_radiotap_header *rthdr =
+ (struct ieee80211_radiotap_header *) skb->data;
+ struct ieee80211_hw_mode *mode = tx->local->hw.conf.mode;
+ int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len);
+
+ /*
+ * default control situation for all injected packets
+ * FIXME: this does not suit all usage cases, expand to allow control
+ */
+ control->retry_limit = 1; /* no retry */
+ control->key_idx = -1; /* no encryption key */
+ control->flags &= ~(IEEE80211_TXCTL_USE_RTS_CTS |
+ IEEE80211_TXCTL_USE_CTS_PROTECT);
+ control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT |
+ IEEE80211_TXCTL_NO_ACK;
+ control->antenna_sel_tx = 0; /* default to default antenna */
+
+ /*
+ * for every radiotap entry that is present
+ * (ieee80211_radiotap_iterator_next returns -ENOENT when no more
+ * entries present, or -EINVAL on error)
+ */
+ while (!ret) {
+ int i, target_rate;
+
+ ret = ieee80211_radiotap_iterator_next(&iterator);
+
+ if (ret)
+ continue;
+
+ /* see if this argument is something we can use */
+ switch (iterator.this_arg_index) {
+ /*
+ * You must take care when dereferencing iterator.this_arg
+ * for multibyte types... the pointer is not aligned. Use
+ * get_unaligned((type *)iterator.this_arg) to dereference
+ * iterator.this_arg for type "type" safely on all arches.
+ */
+ case IEEE80211_RADIOTAP_RATE:
+ /*
+ * radiotap rate u8 is in 500kbps units eg, 0x02=1Mbps
+ * ieee80211 rate int is in 100kbps units eg, 0x0a=1Mbps
+ */
+ target_rate = (*iterator.this_arg) * 5;
+ for (i = 0; i < mode->num_rates; i++) {
+ struct ieee80211_rate *r = &mode->rates[i];
+
+ if (r->rate > target_rate)
+ continue;
+
+ control->rate = r;
+
+ if (r->flags & IEEE80211_RATE_PREAMBLE2)
+ control->tx_rate = r->val2;
+ else
+ control->tx_rate = r->val;
+
+ /* end on exact match */
+ if (r->rate == target_rate)
+ i = mode->num_rates;
+ }
+ break;
+
+ case IEEE80211_RADIOTAP_ANTENNA:
+ /*
+ * radiotap uses 0 for 1st ant, mac80211 is 1 for
+ * 1st ant
+ */
+ control->antenna_sel_tx = (*iterator.this_arg) + 1;
+ break;
+
+ case IEEE80211_RADIOTAP_DBM_TX_POWER:
+ control->power_level = *iterator.this_arg;
+ break;
+
+ case IEEE80211_RADIOTAP_FLAGS:
+ if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FCS) {
+ /*
+ * this indicates that the skb we have been
+ * handed has the 32-bit FCS CRC at the end...
+ * we should react to that by snipping it off
+ * because it will be recomputed and added
+ * on transmission
+ */
+ if (skb->len < (iterator.max_length + FCS_LEN))
+ return TXRX_DROP;
+
+ skb_trim(skb, skb->len - FCS_LEN);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */
+ return TXRX_DROP;
+
+ /*
+ * remove the radiotap header
+ * iterator->max_length was sanity-checked against
+ * skb->len by iterator init
+ */
+ skb_pull(skb, iterator.max_length);
+
+ return TXRX_CONTINUE;
+}
+
+
+static ieee80211_txrx_result inline
__ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
struct sk_buff *skb,
struct net_device *dev,
@@ -1126,6 +1255,8 @@ __ieee80211_tx_prepare(struct ieee80211_
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ ieee80211_txrx_result res = TXRX_CONTINUE;
+
int hdrlen;
memset(tx, 0, sizeof(*tx));
@@ -1135,7 +1266,38 @@ __ieee80211_tx_prepare(struct ieee80211_
tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev);
tx->sta = sta_info_get(local, hdr->addr1);
tx->fc = le16_to_cpu(hdr->frame_control);
+
+ /*
+ * set defaults for things that can be set by
+ * injected radiotap headers
+ */
control->power_level = local->hw.conf.power_level;
+ control->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
+ if (local->sta_antenna_sel != STA_ANTENNA_SEL_AUTO && tx->sta)
+ control->antenna_sel_tx = tx->sta->antenna_sel_tx;
+
+ /*
+ * if the skb came in as in encapsulated injection packet, process
+ * and then remove the radiotap header
+ */
+ if (skb->protocol == ETH_P_80211_RT) {
+
+ printk("__ieee80211_tx_prepare sees ETH_P_80211_RT\n");
+
+ if (__ieee80211_parse_tx_radiotap(tx, skb, control) ==
+ TXRX_DROP) {
+ printk(" drop\n");
+ return TXRX_DROP;
+ }
+ /*
+ * we removed the radiotap header after this point,
+ * we filled control with what we could use
+ * set to the actual ieee header now
+ */
+ hdr = (struct ieee80211_hdr *) skb->data;
+ res = TXRX_QUEUED; /* indication it was injected packet */
+ }
+
tx->u.tx.control = control;
tx->u.tx.unicast = !is_multicast_ether_addr(hdr->addr1);
if (is_multicast_ether_addr(hdr->addr1))
@@ -1152,9 +1314,6 @@ __ieee80211_tx_prepare(struct ieee80211_
control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK;
tx->sta->clear_dst_mask = 0;
}
- control->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
- if (local->sta_antenna_sel != STA_ANTENNA_SEL_AUTO && tx->sta)
- control->antenna_sel_tx = tx->sta->antenna_sel_tx;
hdrlen = ieee80211_get_hdrlen(tx->fc);
if (skb->len > hdrlen + sizeof(rfc1042_header) + 2) {
u8 *pos = &skb->data[hdrlen + sizeof(rfc1042_header)];
@@ -1162,6 +1321,7 @@ __ieee80211_tx_prepare(struct ieee80211_
}
control->flags |= IEEE80211_TXCTL_FIRST_FRAGMENT;
+ return res;
}
static int inline is_ieee80211_device(struct net_device *dev,
@@ -1274,7 +1434,7 @@ static int ieee80211_tx(struct net_devic
struct sta_info *sta;
ieee80211_tx_handler *handler;
struct ieee80211_txrx_data tx;
- ieee80211_txrx_result res = TXRX_DROP;
+ ieee80211_txrx_result res = TXRX_DROP, res_prepare;
int ret, i;
WARN_ON(__ieee80211_queue_pending(local, control->queue));
@@ -1284,15 +1444,26 @@ static int ieee80211_tx(struct net_devic
return 0;
}
- __ieee80211_tx_prepare(&tx, skb, dev, control);
+ res_prepare = __ieee80211_tx_prepare(&tx, skb, dev, control);
+
+ if (res_prepare == TXRX_DROP) {
+ dev_kfree_skb(skb);
+ return 0;
+ }
+
sta = tx.sta;
tx.u.tx.mgmt_interface = mgmt;
tx.u.tx.mode = local->hw.conf.mode;
- for (handler = local->tx_handlers; *handler != NULL; handler++) {
- res = (*handler)(&tx);
- if (res != TXRX_CONTINUE)
- break;
+ if (res_prepare == TXRX_QUEUED) { /* if it was an injected packet */
+ res = TXRX_CONTINUE;
+ } else {
+ for (handler = local->tx_handlers; *handler != NULL;
+ handler++) {
+ res = (*handler)(&tx);
+ if (res != TXRX_CONTINUE)
+ break;
+ }
}
skb = tx.skb; /* handlers are allowed to change skb */
@@ -1493,6 +1664,76 @@ static int ieee80211_master_start_xmit(s
return ret;
}
+/*
+ * snips off the injection encapsulation ethernet header when the packet
+ * has been identified as coming into ieee80211_subif_start_xmit
+ * having the ETH_P_80211_RT type
+ */
+static int
+ieee80211_subif_tx_rt_encap_remove(struct sk_buff *skb, struct net_device *dev,
+ struct ieee80211_sub_if_data *sdata, struct ieee80211_local *local)
+{
+ struct ieee80211_tx_packet_data *pkt_data;
+ struct ieee80211_radiotap_header *prthdr;
+ u16 len;
+
+ /*
+ * snip off the encapsulating ethernet type header
+ * caller ieee80211_subif_start_xmit confirmed we have at least
+ * ETH_HLEN in the skb
+ */
+ skb_pull(skb, ETH_HLEN);
+ prthdr = (struct ieee80211_radiotap_header *)skb->data;
+ /*
+ * there must be a radiotap header at the
+ * start in this case
+ */
+ if (unlikely(skb->len < sizeof(*prthdr))) {
+ printk(KERN_DEBUG "%s: short skb (len=%d)\n",
+ dev->name, skb->len);
+ return -EINVAL;
+ }
+ /*
+ * only version 0 is supported... must check here because
+ * we are interested in the length inside in a moment
+ */
+ if (unlikely(prthdr->it_version))
+ return -EINVAL;
+
+ skb->dev = local->mdev;
+ pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
+ memset(pkt_data, 0, sizeof(*pkt_data));
+ /* needed because we set skb device to master */
+ pkt_data->ifindex = sdata->dev->ifindex;
+ pkt_data->mgmt_iface = 0;
+ pkt_data->do_not_encrypt = 1;
+ /*
+ * fix up the skb pointers accounting for the radiotap
+ * header still being in there. We are being given
+ * a precooked IEEE80211 header so no need for
+ * normal processing
+ */
+ len = le16_to_cpu(get_unaligned(&prthdr->it_len));
+ /*
+ * detect possible insantity with the reported rt length
+ * vs the actual skb length
+ */
+ if (unlikely(skb->len < (sizeof(*prthdr) + len))) {
+ printk(KERN_DEBUG "%s: short skb (len=%d)\n",
+ dev->name, skb->len);
+ return -EINVAL;
+ }
+ skb_set_mac_header(skb, len);
+ skb_set_network_header(skb, len + sizeof(struct ieee80211_hdr));
+ skb_set_transport_header(skb, len + sizeof(struct ieee80211_hdr));
+ /*
+ * mark the SKB as having had the encapsulation so we can recognize
+ * that this is an injected packet with radiotap subsequently
+ */
+ skb->protocol = ETH_P_80211_RT;
+
+ return 0;
+}
/**
* ieee80211_subif_start_xmit - netif start_xmit function for Ethernet-type
@@ -1537,6 +1778,28 @@ static int ieee80211_subif_start_xmit(st
/* convert Ethernet header to proper 802.11 header (based on
* operation mode) */
ethertype = (skb->data[12] << 8) | skb->data[13];
+
+ /*
+ * Case where an injected radiotap + 80211 packet is encapsulated
+ * in a ETH_P_80211_RT frame
+ */
+ if (ethertype == ETH_P_80211_RT) {
+ ret = 0; /* we should free the skb on fail */
+ /*
+ * strip the encapsulating ethernet header and mark skb's
+ * protocol as being ETH_P_80211_RT
+ */
+ if (ieee80211_subif_tx_rt_encap_remove(skb, dev, sdata, local))
+ goto fail;
+ /*
+ * pass the remaining radiotap header + 80211 header + payload
+ * up to the next stage
+ */
+ dev_queue_xmit(skb);
+
+ return 0;
+ }
+
/* TODO: handling for 802.1x authorized/unauthorized port */
fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA;
--
^ permalink raw reply [flat|nested] 8+ messages in thread