* [PATCH Try#9 1/4] mac80211: Monitor mode radiotap injection docs
2007-06-11 15:21 [PATCH Try#9 0/4] Radiotap injection for Monitor Mode andy
@ 2007-06-11 15:21 ` andy
2007-06-11 15:21 ` [PATCH Try#9 2/4] mac80211: Define present bitmap extend bit mask andy
` (2 subsequent siblings)
3 siblings, 0 replies; 7+ messages in thread
From: andy @ 2007-06-11 15:21 UTC (permalink / raw)
To: linux-wireless; +Cc: Andy Green
From: Andy Green <andy@warmcat.com>
Signed-off-by: Andy Green <andy@warmcat.com>
---
Documentation/networking/mac80211-injection.txt | 59 +++++++++++++++++
Documentation/networking/radiotap-headers.txt | 79 ++++++++++++++++++++++++
2 files changed, 138 insertions(+)
Index: wireless-dev/Documentation/networking/mac80211-injection.txt
===================================================================
--- /dev/null
+++ wireless-dev/Documentation/networking/mac80211-injection.txt
@@ -0,0 +1,59 @@
+How to use packet injection with mac80211
+=========================================
+
+mac80211 now allows arbitrary packets to be injected down any Monitor Mode
+interface from userland. The packet you inject needs to be composed in the
+following format:
+
+ [ radiotap header ]
+ [ ieee80211 header ]
+ [ payload ]
+
+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
+
+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.
+
+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,79 @@
+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 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] 7+ messages in thread* [PATCH Try#9 2/4] mac80211: Define present bitmap extend bit mask
2007-06-11 15:21 [PATCH Try#9 0/4] Radiotap injection for Monitor Mode andy
2007-06-11 15:21 ` [PATCH Try#9 1/4] mac80211: Monitor mode radiotap injection docs andy
@ 2007-06-11 15:21 ` andy
2007-06-11 15:21 ` [PATCH Try#9 3/4] cfg80211: Radiotap parser andy
2007-06-11 15:21 ` [PATCH Try#9 4/4] mac80211: Monitor mode radiotap-based packet injection andy
3 siblings, 0 replies; 7+ messages in thread
From: andy @ 2007-06-11 15:21 UTC (permalink / raw)
To: linux-wireless; +Cc: Andy Green
Used to detect if the field presence mask is extended
Signed-off-by: Andy Green <andy@warmcat.com>
---
include/net/ieee80211_radiotap.h | 2 ++
1 file changed, 2 insertions(+)
Index: wireless-dev/include/net/ieee80211_radiotap.h
===================================================================
--- wireless-dev.orig/include/net/ieee80211_radiotap.h
+++ wireless-dev/include/net/ieee80211_radiotap.h
@@ -90,6 +90,8 @@ struct ieee80211_radiotap_header {
*/
};
+#define IEEE80211_RADIOTAP_PRESENT_EXTEND_MASK 0x80000000
+
/* Name Data type Units
* ---- --------- -----
*
--
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH Try#9 3/4] cfg80211: Radiotap parser
2007-06-11 15:21 [PATCH Try#9 0/4] Radiotap injection for Monitor Mode andy
2007-06-11 15:21 ` [PATCH Try#9 1/4] mac80211: Monitor mode radiotap injection docs andy
2007-06-11 15:21 ` [PATCH Try#9 2/4] mac80211: Define present bitmap extend bit mask andy
@ 2007-06-11 15:21 ` andy
2007-06-12 8:09 ` Michael Wu
2007-06-11 15:21 ` [PATCH Try#9 4/4] mac80211: Monitor mode radiotap-based packet injection andy
3 siblings, 1 reply; 7+ messages in thread
From: andy @ 2007-06-11 15:21 UTC (permalink / raw)
To: linux-wireless; +Cc: 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 #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).
Signed-off-by: Andy Green <andy@warmcat.com>
===================================================
---
Documentation/networking/radiotap-headers.txt | 56 +++++
include/net/cfg80211.h | 39 +++
net/wireless/Makefile | 2
net/wireless/radiotap.c | 256 ++++++++++++++++++++++++++
4 files changed, 352 insertions(+), 1 deletion(-)
Index: wireless-dev/include/net/cfg80211.h
===================================================================
--- wireless-dev.orig/include/net/cfg80211.h
+++ wireless-dev/include/net/cfg80211.h
@@ -74,6 +74,45 @@ 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,256 @@
+/*
+ * Radiotap parser
+ *
+ * Copyright 2007 Andy Green <andy@warmcat.com>
+ */
+
+#include <linux/if.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <net/genetlink.h>
+#include <net/cfg80211.h>
+#include <net/wireless.h>
+#include "nl80211.h"
+#include "core.h"
+#include <net/ieee80211_radiotap.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 on success or negative if sanity check fails
+ *
+ * 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)
+ * then loop calling __ieee80211_radiotap_iterator_next()... it returns either a
+ * negative error code if there are no more args in the header, or the
+ * next argument type index that is present. 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.
+ *
+ * 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(radiotap_header->it_len)))
+ return -EINVAL;
+
+ iterator->rtheader = radiotap_header;
+ iterator->max_length = le16_to_cpu(radiotap_header->it_len);
+ iterator->arg_index = 0;
+ iterator->bitmap_shifter = le32_to_cpu(radiotap_header->it_present);
+ iterator->arg = ((u8 *)radiotap_header) +
+ sizeof(struct ieee80211_radiotap_header);
+ iterator->this_arg = 0;
+
+ /* find payload start allowing for extended bitmap(s) */
+
+ if (unlikely(iterator->bitmap_shifter &
+ IEEE80211_RADIOTAP_PRESENT_EXTEND_MASK)) {
+ while (le32_to_cpu(*((u32 *)iterator->arg)) &
+ IEEE80211_RADIOTAP_PRESENT_EXTEND_MASK) {
+ 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 ((((int)iterator->arg) - ((int)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: next present arg index on success or negative if no more or error
+ *
+ * This function returns the next radiotap arg index (IEEE80211_RADIOTAP_*)
+ * and sets iterator->this_arg to point to the payload for the arg. It takes
+ * care of alignment handling and extended present fields. iterator->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.
+ */
+
+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;
+
+ 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.
+ */
+
+ if ((((int)iterator->arg)-((int)iterator->rtheader)) &
+ ((rt_sizes[iterator->arg_index] >> 4) - 1))
+ iterator->arg_index +=
+ (rt_sizes[iterator->arg_index] >> 4) -
+ ((((int)iterator->arg) -
+ ((int)iterator->rtheader)) &
+ ((rt_sizes[iterator->arg_index] >> 4) - 1));
+
+ /*
+ * 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 ((((int)iterator->arg) - ((int)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(
+ *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 iterator->this_arg_index;
+
+ }
+
+ /* 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
@@ -76,4 +76,60 @@ 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;
+
+ if (ieee80211_radiotap_iterator_init(&iterator, buf, buflen) < 0)
+ return -EINVAL;
+
+ while (ieee80211_radiotap_iterator_next(&iterator) >= 0) {
+ int i, target_rate;
+
+ /* see if this argument is something we can use */
+
+ switch (iterator.this_arg_index) {
+
+ 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 */
+
+ /* discard the radiotap header part */
+
+ buf += iterator->max_length;
+ buflen -= iterator->max_length;
+
+ ...
+
+}
+
Andy Green <andy@warmcat.com>
--
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [PATCH Try#9 3/4] cfg80211: Radiotap parser
2007-06-11 15:21 ` [PATCH Try#9 3/4] cfg80211: Radiotap parser andy
@ 2007-06-12 8:09 ` Michael Wu
0 siblings, 0 replies; 7+ messages in thread
From: Michael Wu @ 2007-06-12 8:09 UTC (permalink / raw)
To: andy; +Cc: linux-wireless
[-- Attachment #1: Type: text/plain, Size: 5653 bytes --]
On Monday 11 June 2007 08:21, andy@warmcat.com wrote:
> +struct ieee80211_radiotap_iterator {
> + struct ieee80211_radiotap_header *rtheader;
> + int max_length;
> + int this_arg_index;
> + u8 * this_arg;
^
Eliminate the space here between * and this_arg.
> +
> + int arg_index;
> + u8 * arg;
And here. ^
> + __le32 *next_bitmap;
> + u32 bitmap_shifter;
> +};
> +
> +extern int ieee80211_radiotap_iterator_init(
> + struct ieee80211_radiotap_iterator * iterator,
Here. ^
> + struct ieee80211_radiotap_header * radiotap_header,
You get the idea. ^
> Index: wireless-dev/net/wireless/radiotap.c
> ===================================================================
> --- /dev/null
> +++ wireless-dev/net/wireless/radiotap.c
> @@ -0,0 +1,256 @@
> +/*
> + * Radiotap parser
> + *
> + * Copyright 2007 Andy Green <andy@warmcat.com>
> + */
> +
> +#include <linux/if.h>
Don't think anything from here is used.
> +#include <linux/err.h>
> +#include <linux/mutex.h>
We don't touch any mutexes in this file..
> +#include <linux/device.h>
Nor do we care about devices.
> +#include <net/genetlink.h>
Or netlink.
> +#include <net/cfg80211.h>
> +#include <net/wireless.h>
Or wiphys.
> +#include "nl80211.h"
> +#include "core.h"
nl80211.h and core.h seem unnecessary too.
All these includes might be pulling some other header that you do need,
however. (linux/kernel.h probably covers it..)
> +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 */
> +
I think the code would look better without a blank line following the comment.
> + if (radiotap_header->it_version)
> + return -EINVAL;
> +
> + /* sanity check for allowed length and radiotap length field */
> +
> + if (max_length < (le16_to_cpu(radiotap_header->it_len)))
Unnecessary parenthesis. ^ ^
> + return -EINVAL;
> +
> + iterator->rtheader = radiotap_header;
> + iterator->max_length = le16_to_cpu(radiotap_header->it_len);
> + iterator->arg_index = 0;
> + iterator->bitmap_shifter = le32_to_cpu(radiotap_header->it_present);
> + iterator->arg = ((u8 *)radiotap_header) +
Ditto. ^ ^
> + sizeof(struct ieee80211_radiotap_header);
I usually like to use sizeof on a variable (eg., sizeof(*radiotap_header))
since it's shorter and doesn't need to be changed if the variable type
changes.
> + iterator->this_arg = 0;
> +
> + /* find payload start allowing for extended bitmap(s) */
> +
> + if (unlikely(iterator->bitmap_shifter &
> + IEEE80211_RADIOTAP_PRESENT_EXTEND_MASK)) {
+--------^
Indenting this a bit more to the right should look better.
> + while (le32_to_cpu(*((u32 *)iterator->arg)) &
> + IEEE80211_RADIOTAP_PRESENT_EXTEND_MASK) {
+--------------^
Ditto.
> + 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 ((((int)iterator->arg) - ((int)iterator->rtheader)) >
> + iterator->max_length)
For pointer arithmetic, you should use unsigned long. The parenthesis are a
little too paranoid here too.
> + if ((((int)iterator->arg)-((int)iterator->rtheader)) &
unsigned long for pointer arithmetic and reduce parenthesis, as before. Seems
to be a lot of this, so I won't mention it again.
> + ((rt_sizes[iterator->arg_index] >> 4) - 1))
> + iterator->arg_index +=
> + (rt_sizes[iterator->arg_index] >> 4) -
> + ((((int)iterator->arg) -
> + ((int)iterator->rtheader)) &
> + ((rt_sizes[iterator->arg_index] >> 4) - 1));
> +
> + /*
> + * 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 ((((int)iterator->arg) - ((int)iterator->rtheader)) >
> + iterator->max_length)
> + return -EINVAL;
> +
> + next_entry:
> +
A blank line after a label doesn't look right to me..
> + 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(
> + *iterator->next_bitmap);
Move "le32_to_cpu(" down to the next line.
> + 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 iterator->this_arg_index;
> +
Another unnecessary blank line. ;)
Thanks,
-Michael Wu
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH Try#9 4/4] mac80211: Monitor mode radiotap-based packet injection
2007-06-11 15:21 [PATCH Try#9 0/4] Radiotap injection for Monitor Mode andy
` (2 preceding siblings ...)
2007-06-11 15:21 ` [PATCH Try#9 3/4] cfg80211: Radiotap parser andy
@ 2007-06-11 15:21 ` andy
2007-06-12 8:23 ` Michael Wu
3 siblings, 1 reply; 7+ messages in thread
From: andy @ 2007-06-11 15:21 UTC (permalink / raw)
To: linux-wireless; +Cc: Andy Green
From: Andy Green <andy@warmcat.com>
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
Signed-off-by: Andy Green <andy@warmcat.com>
---
net/mac80211/ieee80211.c | 212 ++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 202 insertions(+), 10 deletions(-)
Index: wireless-dev/net/mac80211/ieee80211.c
===================================================================
--- wireless-dev.orig/net/mac80211/ieee80211.c
+++ wireless-dev/net/mac80211/ieee80211.c
@@ -1118,7 +1118,113 @@ 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_convert_radiotap_to_control_and_remove(
+ 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 little-endian
+ */
+
+ struct ieee80211_radiotap_iterator iterator;
+ struct ieee80211_radiotap_header *rthdr =
+ (struct ieee80211_radiotap_header *) skb->data;
+ struct ieee80211_hw_mode *hw_mode=tx->local->hw.conf.mode;
+
+ /* this can fail some sanity checks, drop packet if it does so */
+
+ if (ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len) < 0)
+ return TXRX_DROP;
+
+ /*
+ * 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 (returns -ve on end or
+ * on error)
+ */
+
+ while (ieee80211_radiotap_iterator_next(&iterator) >= 0) {
+ int i, target_rate;
+
+ /* see if this argument is something we can use */
+
+ switch (iterator.this_arg_index) {
+
+ 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 < hw_mode->num_rates; i++) {
+ struct ieee80211_rate *r = &hw_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 = hw_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;
+
+ default:
+ break;
+ }
+ }
+
+ /*
+ * remove the radiotap header
+ * rthdr->it_len was sanity-checked against skb->len by iterator init
+ */
+ skb_pull(skb, le16_to_cpu(rthdr->it_len));
+
+ 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 +1232,9 @@ __ieee80211_tx_prepare(struct ieee80211_
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ struct ieee80211_sub_if_data *sdata;
+ ieee80211_txrx_result res = TXRX_CONTINUE;
+
int hdrlen;
memset(tx, 0, sizeof(*tx));
@@ -1135,7 +1244,33 @@ __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;
+
+ /* process and remove the injection radiotap header */
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ if (unlikely(sdata->type == IEEE80211_IF_TYPE_MNTR)) {
+ if (__ieee80211_convert_radiotap_to_control_and_remove(
+ tx, skb, control) == TXRX_DROP) {
+ 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 monitor 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 +1287,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 +1294,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 +1407,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 +1417,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 */
@@ -1531,6 +1675,54 @@ static int ieee80211_subif_start_xmit(st
goto fail;
}
+ if (unlikely(sdata->type == IEEE80211_IF_TYPE_MNTR)) {
+ struct ieee80211_radiotap_header * prthdr =
+ (struct ieee80211_radiotap_header *)skb->data;
+
+ /*
+ * there must be a radiotap header at the
+ * start in this case
+ */
+
+ if (unlikely(prthdr->it_version)) {
+ /* only version 0 is supported */
+ ret = 0;
+ goto fail;
+ }
+
+ skb->dev = local->mdev;
+
+ pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
+ memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
+ pkt_data->ifindex = sdata->dev->ifindex;
+ pkt_data->mgmt_iface = 0;
+ pkt_data->do_not_encrypt = 1;
+
+ /* above needed because we set skb device to master */
+
+ /*
+ * fix up the pointers accounting for the radiotap
+ * header still being in there. We are being given
+ * a precooked IEEE80211 header so no need for
+ * normal processing
+ */
+
+ skb_set_mac_header(skb, prthdr->it_len);
+ skb_set_network_header(skb, prthdr->it_len +
+ sizeof(struct ieee80211_hdr));
+ skb_set_transport_header(skb, prthdr->it_len +
+ sizeof(struct ieee80211_hdr));
+
+ /*
+ * pass the radiotap header up to
+ * the next stage intact
+ */
+
+ dev_queue_xmit(skb);
+
+ return 0;
+ }
+
nh_pos = skb_network_header(skb) - skb->data;
h_pos = skb_transport_header(skb) - skb->data;
--
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [PATCH Try#9 4/4] mac80211: Monitor mode radiotap-based packet injection
2007-06-11 15:21 ` [PATCH Try#9 4/4] mac80211: Monitor mode radiotap-based packet injection andy
@ 2007-06-12 8:23 ` Michael Wu
0 siblings, 0 replies; 7+ messages in thread
From: Michael Wu @ 2007-06-12 8:23 UTC (permalink / raw)
To: andy; +Cc: linux-wireless
[-- Attachment #1: Type: text/plain, Size: 1649 bytes --]
On Monday 11 June 2007 08:21, andy@warmcat.com wrote:
> +__ieee80211_convert_radiotap_to_control_and_remove(
This is kinda long.. how about ieee80211_parse_radiotap instead? Function
names aren't a substitute for comments. ;)
> + struct ieee80211_hw_mode *hw_mode=tx->local->hw.conf.mode;
Add a space before and after the '='. Also, mode is more common than hw_mode
as a variable name for struct ieee80211_hw_mode.
> +
> + /* this can fail some sanity checks, drop packet if it does so */
> +
> + if (ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len) < 0)
> + return TXRX_DROP;
> +
> + /*
> + * 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 (returns -ve on end or
-ve?
> + * on error)
> + */
> +
> + while (ieee80211_radiotap_iterator_next(&iterator) >= 0) {
> + int i, target_rate;
> +
> + /* see if this argument is something we can use */
> +
> + switch (iterator.this_arg_index) {
> +
An empty line after a switch statement doesn't seem right.
I think the rest of the patch is okay. Just keep in mind the other style
comments I made in the other patch.
Thanks,
-Michael Wu
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 7+ messages in thread