* [PATCH 1/3] mac80211: Add radiotap support
2007-03-19 11:01 [PATCH 0/3] Try #4: Radiotap on Monitor Mode interfaces for rx and tx andy
@ 2007-03-19 11:01 ` andy
2007-03-19 17:15 ` Michael Wu
2007-03-19 11:01 ` [PATCH 2/3] mac80211: Monitor mode radiotap-based packet injection andy
2007-03-19 11:01 ` [PATCH 3/3] mac80211: Monitor mode radiotap injection docs andy
2 siblings, 1 reply; 6+ messages in thread
From: andy @ 2007-03-19 11:01 UTC (permalink / raw)
To: linux-wireless
From: Michael Wu <flamingice@sourmilk.net>
---
include/net/mac80211.h | 3 ++
net/mac80211/ieee80211.c | 69 +++++++++++++++++++++++++++++++++-------
net/mac80211/ieee80211_iface.c | 2 +
3 files changed, 61 insertions(+), 13 deletions(-)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 916b21b..050f126 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -529,6 +529,9 @@ struct ieee80211_hw {
* per-packet RC4 key with each TX frame when doing hwcrypto */
#define IEEE80211_HW_TKIP_REQ_PHASE2_KEY (1<<14)
+ /* Driver supports radiotap. Temporary until all drivers support it. */
+#define IEEE80211_HW_RADIOTAP_SUPPORTED (1<<20)
+
u32 flags; /* hardware flags defined above */
/* Set to the size of a needed device specific skb headroom for TX skbs. */
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c
index 0b7cb35..c3a9f0e 100644
--- a/net/mac80211/ieee80211.c
+++ b/net/mac80211/ieee80211.c
@@ -8,6 +8,7 @@
*/
#include <net/mac80211.h>
+#include <net/ieee80211_radiotap.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/netdevice.h>
@@ -286,6 +287,14 @@ int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb)
}
EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb);
+static int ieee80211_get_radiotap_len(struct sk_buff *skb)
+{
+ struct ieee80211_radiotap_header *hdr =
+ (struct ieee80211_radiotap_header *) skb->data;
+
+ return le16_to_cpu(hdr->it_len);
+}
+
#ifdef CONFIG_MAC80211_LOWTX_FRAME_DUMP
static void ieee80211_dump_frame(const char *ifname, const char *title,
const struct sk_buff *skb)
@@ -2741,26 +2750,50 @@ ieee80211_rx_monitor(struct net_device *dev, struct sk_buff *skb,
struct ieee80211_rx_status *status)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_frame_info *fi;
struct ieee80211_sub_if_data *sdata;
- const size_t hlen = sizeof(struct ieee80211_frame_info)
- - sizeof(fi->msg_type);
+ struct ieee80211_rtap_hdr {
+ struct ieee80211_radiotap_header hdr;
+ u8 flags;
+ u8 pad0;
+ u8 rate;
+ u8 pad1;
+ __le16 chan_freq;
+ __le16 chan_flags;
+ u8 antsignal;
+ } __attribute__ ((packed)) *rthdr;
skb->dev = dev;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- if (skb_headroom(skb) < hlen) {
- I802_DEBUG_INC(local->rx_expand_skb_head);
- if (pskb_expand_head(skb, hlen, 0, GFP_ATOMIC)) {
- dev_kfree_skb(skb);
- return;
+ if (!(local->hw.flags & IEEE80211_HW_RADIOTAP_SUPPORTED)) {
+ if (skb_headroom(skb) < sizeof(*rthdr)) {
+ I802_DEBUG_INC(local->rx_expand_skb_head);
+ if (pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC)) {
+ dev_kfree_skb(skb);
+ return;
+ }
}
- }
- fi = (struct ieee80211_frame_info *) skb_push(skb, hlen);
+ rthdr = (struct ieee80211_rtap_hdr *) skb_push(skb, sizeof(*rthdr));
+ memset(rthdr, 0, sizeof(*rthdr));
+ rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr));
+ rthdr->hdr.it_present =
+ cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) ||
+ (1 << IEEE80211_RADIOTAP_RATE) ||
+ (1 << IEEE80211_RADIOTAP_CHANNEL) ||
+ (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL));
+ rthdr->flags = local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS ?
+ IEEE80211_RADIOTAP_F_FCS : 0;
+ rthdr->rate = status->rate / 5;
+ rthdr->chan_freq = cpu_to_le16(status->freq);
+ rthdr->chan_flags =
+ status->phymode == MODE_IEEE80211A ?
+ cpu_to_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ) :
+ cpu_to_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ);
+ rthdr->antsignal = status->ssi;
+ }
- ieee80211_fill_frame_info(local, fi, status);
sdata->stats.rx_packets++;
sdata->stats.rx_bytes += skb->len;
@@ -3164,6 +3197,10 @@ ieee80211_rx_h_monitor(struct ieee80211_txrx_data *rx)
return TXRX_QUEUED;
}
+ if (rx->local->monitors &&
+ rx->local->hw.flags & IEEE80211_HW_RADIOTAP_SUPPORTED)
+ skb_pull(rx->skb, ieee80211_get_radiotap_len(rx->skb));
+
return TXRX_CONTINUE;
}
@@ -3731,6 +3768,13 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ieee80211_txrx_data rx;
u16 type;
int multicast;
+ int radiotap_len = 0;
+
+ if (local->monitors &&
+ local->hw.flags & IEEE80211_HW_RADIOTAP_SUPPORTED) {
+ radiotap_len = ieee80211_get_radiotap_len(skb);
+ skb_pull(skb, radiotap_len);
+ }
hdr = (struct ieee80211_hdr *) skb->data;
memset(&rx, 0, sizeof(rx));
@@ -3767,6 +3811,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
goto end;
skb = rx.skb;
+ skb_push(skb, radiotap_len);
if (sta && !sta->assoc_ap && !(sta->flags & WLAN_STA_WDS) &&
!local->iff_promiscs && !multicast) {
rx.u.rx.ra_match = 1;
@@ -3775,7 +3820,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
} else {
struct ieee80211_sub_if_data *prev = NULL;
struct sk_buff *skb_new;
- u8 *bssid = ieee80211_get_bssid(hdr, skb->len);
+ u8 *bssid = ieee80211_get_bssid(hdr, skb->len - radiotap_len);
list_for_each_entry(sdata, &local->sub_if_list, list) {
rx.u.rx.ra_match = 1;
diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c
index 3e0b4fa..51197b1 100644
--- a/net/mac80211/ieee80211_iface.c
+++ b/net/mac80211/ieee80211_iface.c
@@ -199,7 +199,7 @@ void ieee80211_if_set_type(struct net_device *dev, int type)
break;
}
case IEEE80211_IF_TYPE_MNTR:
- dev->type = ARPHRD_IEEE80211_PRISM;
+ dev->type = ARPHRD_IEEE80211_RADIOTAP;
break;
default:
printk(KERN_WARNING "%s: %s: Unknown interface type 0x%x",
--
^ permalink raw reply related [flat|nested] 6+ messages in thread* Re: [PATCH 1/3] mac80211: Add radiotap support
2007-03-19 11:01 ` [PATCH 1/3] mac80211: Add radiotap support andy
@ 2007-03-19 17:15 ` Michael Wu
2007-03-20 10:16 ` Andy Green
0 siblings, 1 reply; 6+ messages in thread
From: Michael Wu @ 2007-03-19 17:15 UTC (permalink / raw)
To: andy; +Cc: linux-wireless
[-- Attachment #1.1: Type: text/plain, Size: 467 bytes --]
On Monday 19 March 2007 07:01, andy@warmcat.com wrote:
> + struct ieee80211_rtap_hdr {
> + struct ieee80211_radiotap_header hdr;
> + u8 flags;
> + u8 pad0;
> + u8 rate;
> + u8 pad1;
> + __le16 chan_freq;
> + __le16 chan_flags;
> + u8 antsignal;
> + } __attribute__ ((packed)) *rthdr;
>
Looks like I screwed up the padding there. New patch without the padding
attached. Probably explains why rate isn't being reported correctly..
-Michael Wu
[-- Attachment #1.2: radio.diff --]
[-- Type: text/x-diff, Size: 5613 bytes --]
mac80211: Add radiotap support
From: Michael Wu <flamingice@sourmilk.net>
---
include/net/mac80211.h | 3 ++
net/mac80211/ieee80211.c | 67 +++++++++++++++++++++++++++++++++-------
net/mac80211/ieee80211_iface.c | 2 +
3 files changed, 59 insertions(+), 13 deletions(-)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 916b21b..27cffdc 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -518,6 +518,9 @@ struct ieee80211_hw {
* normal operation. */
#define IEEE80211_HW_MONITOR_DURING_OPER (1<<9)
+ /* Driver supports radiotap. */
+#define IEEE80211_HW_RADIOTAP_SUPPORTED (1<<10)
+
/* please fill this gap when adding new flags */
/* calculate Michael MIC for an MSDU when doing hwcrypto */
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c
index 0b7cb35..6bffc29 100644
--- a/net/mac80211/ieee80211.c
+++ b/net/mac80211/ieee80211.c
@@ -8,6 +8,7 @@
*/
#include <net/mac80211.h>
+#include <net/ieee80211_radiotap.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/netdevice.h>
@@ -286,6 +287,14 @@ int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb)
}
EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb);
+static int ieee80211_get_radiotap_len(struct sk_buff *skb)
+{
+ struct ieee80211_radiotap_header *hdr =
+ (struct ieee80211_radiotap_header *) skb->data;
+
+ return le16_to_cpu(hdr->it_len);
+}
+
#ifdef CONFIG_MAC80211_LOWTX_FRAME_DUMP
static void ieee80211_dump_frame(const char *ifname, const char *title,
const struct sk_buff *skb)
@@ -2741,26 +2750,48 @@ ieee80211_rx_monitor(struct net_device *dev, struct sk_buff *skb,
struct ieee80211_rx_status *status)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_frame_info *fi;
struct ieee80211_sub_if_data *sdata;
- const size_t hlen = sizeof(struct ieee80211_frame_info)
- - sizeof(fi->msg_type);
+ struct ieee80211_rtap_hdr {
+ struct ieee80211_radiotap_header hdr;
+ u8 flags;
+ u8 rate;
+ __le16 chan_freq;
+ __le16 chan_flags;
+ u8 antsignal;
+ } __attribute__ ((packed)) *rthdr;
skb->dev = dev;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- if (skb_headroom(skb) < hlen) {
- I802_DEBUG_INC(local->rx_expand_skb_head);
- if (pskb_expand_head(skb, hlen, 0, GFP_ATOMIC)) {
- dev_kfree_skb(skb);
- return;
+ if (!(local->hw.flags & IEEE80211_HW_RADIOTAP_SUPPORTED)) {
+ if (skb_headroom(skb) < sizeof(*rthdr)) {
+ I802_DEBUG_INC(local->rx_expand_skb_head);
+ if (pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC)) {
+ dev_kfree_skb(skb);
+ return;
+ }
}
- }
- fi = (struct ieee80211_frame_info *) skb_push(skb, hlen);
+ rthdr = (struct ieee80211_rtap_hdr *) skb_push(skb, sizeof(*rthdr));
+ memset(rthdr, 0, sizeof(*rthdr));
+ rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr));
+ rthdr->hdr.it_present =
+ cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) ||
+ (1 << IEEE80211_RADIOTAP_RATE) ||
+ (1 << IEEE80211_RADIOTAP_CHANNEL) ||
+ (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL));
+ rthdr->flags = local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS ?
+ IEEE80211_RADIOTAP_F_FCS : 0;
+ rthdr->rate = status->rate / 5;
+ rthdr->chan_freq = cpu_to_le16(status->freq);
+ rthdr->chan_flags =
+ status->phymode == MODE_IEEE80211A ?
+ cpu_to_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ) :
+ cpu_to_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ);
+ rthdr->antsignal = status->ssi;
+ }
- ieee80211_fill_frame_info(local, fi, status);
sdata->stats.rx_packets++;
sdata->stats.rx_bytes += skb->len;
@@ -3164,6 +3195,10 @@ ieee80211_rx_h_monitor(struct ieee80211_txrx_data *rx)
return TXRX_QUEUED;
}
+ if (rx->local->monitors &&
+ rx->local->hw.flags & IEEE80211_HW_RADIOTAP_SUPPORTED)
+ skb_pull(rx->skb, ieee80211_get_radiotap_len(rx->skb));
+
return TXRX_CONTINUE;
}
@@ -3731,6 +3766,13 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ieee80211_txrx_data rx;
u16 type;
int multicast;
+ int radiotap_len = 0;
+
+ if (local->monitors &&
+ local->hw.flags & IEEE80211_HW_RADIOTAP_SUPPORTED) {
+ radiotap_len = ieee80211_get_radiotap_len(skb);
+ skb_pull(skb, radiotap_len);
+ }
hdr = (struct ieee80211_hdr *) skb->data;
memset(&rx, 0, sizeof(rx));
@@ -3767,6 +3809,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
goto end;
skb = rx.skb;
+ skb_push(skb, radiotap_len);
if (sta && !sta->assoc_ap && !(sta->flags & WLAN_STA_WDS) &&
!local->iff_promiscs && !multicast) {
rx.u.rx.ra_match = 1;
@@ -3775,7 +3818,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
} else {
struct ieee80211_sub_if_data *prev = NULL;
struct sk_buff *skb_new;
- u8 *bssid = ieee80211_get_bssid(hdr, skb->len);
+ u8 *bssid = ieee80211_get_bssid(hdr, skb->len - radiotap_len);
list_for_each_entry(sdata, &local->sub_if_list, list) {
rx.u.rx.ra_match = 1;
diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c
index 3e0b4fa..51197b1 100644
--- a/net/mac80211/ieee80211_iface.c
+++ b/net/mac80211/ieee80211_iface.c
@@ -199,7 +199,7 @@ void ieee80211_if_set_type(struct net_device *dev, int type)
break;
}
case IEEE80211_IF_TYPE_MNTR:
- dev->type = ARPHRD_IEEE80211_PRISM;
+ dev->type = ARPHRD_IEEE80211_RADIOTAP;
break;
default:
printk(KERN_WARNING "%s: %s: Unknown interface type 0x%x",
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply related [flat|nested] 6+ messages in thread* Re: [PATCH 1/3] mac80211: Add radiotap support
2007-03-19 17:15 ` Michael Wu
@ 2007-03-20 10:16 ` Andy Green
0 siblings, 0 replies; 6+ messages in thread
From: Andy Green @ 2007-03-20 10:16 UTC (permalink / raw)
To: Michael Wu; +Cc: linux-wireless
Michael Wu wrote:
Hi Michael -
> + rthdr->hdr.it_present =
> + cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) ||
> + (1 << IEEE80211_RADIOTAP_RATE) ||
> + (1 << IEEE80211_RADIOTAP_CHANNEL) ||
> + (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL));
These were the wrong kind of OR operator as well.
test.c:
#include <stdio.h>
int main() { printf("%d %d\n", 1 || 2, 1 | 2); return 0; }
$ gcc test.c
$ ./a.out
1 3
After fixing that it now works with tcpdump!
# tcpdump -i mon0 -s0 -X ether host 13:22:33:44:55:66
09:54:58.579725 1.0 Mb/s 2417 MHz (0x0480) 100dB signal
13:22:33:44:55:66 (oui Unknown) Unknown SSAP 0x60 > 13:22:33:44:55:66
(oui Unknown) Unknown DSAP 0x50 Unnumbered, ua, Flags [Command], length 38
0x0000: 5061 636b 6574 7370 616d 6d65 7220 6272 Packetspammer.br
0x0010: 6f61 6463 6173 7420 7061 636b 6574 2031 oadcast.packet.1
0x0020: 3639 72b1 0066 69r..f
09:54:58.679197 54.0 Mb/s 2417 MHz (0x0480) 100dB signal
13:22:33:44:55:66 (oui Unknown) Unknown SSAP 0x60 > 13:22:33:44:55:66
(oui Unknown) Unknown DSAP 0x50 Unnumbered, ua, Flags [Command], length 38
0x0000: 5061 636b 6574 7370 616d 6d65 7220 6272 Packetspammer.br
0x0010: 6f61 6463 6173 7420 7061 636b 6574 2031 oadcast.packet.1
0x0020: 3730 c01d 92cd 70....
Note the CRC appears, I guess it's okay. With zd1211rw-mac80211 as it
is, rx strength always appears as 100dB: it comes from
ieee80211_rx_status.ssi. 1Mbps injection is working as well since a
couple of tries ago on my patch.
-Andy
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 2/3] mac80211: Monitor mode radiotap-based packet injection
2007-03-19 11:01 [PATCH 0/3] Try #4: Radiotap on Monitor Mode interfaces for rx and tx andy
2007-03-19 11:01 ` [PATCH 1/3] mac80211: Add radiotap support andy
@ 2007-03-19 11:01 ` andy
2007-03-19 11:01 ` [PATCH 3/3] mac80211: Monitor mode radiotap injection docs andy
2 siblings, 0 replies; 6+ messages in thread
From: andy @ 2007-03-19 11:01 UTC (permalink / raw)
To: linux-wireless
From: Andy Green <andy@warmcat.com>
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
===================================================
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c
index fb33b90..fe15612 100644
--- a/net/mac80211/ieee80211.c
+++ b/net/mac80211/ieee80211.c
@@ -1054,7 +1054,180 @@ ieee80211_tx_h_ps_buf(struct ieee80211_txrx_data *tx)
}
-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 the radiotap header that
+ * must be at the start of the packet injected in Monitor
+ * mode into control and then discard the radiotap header
+ *
+ * Need to take some care with endian-ness since radiotap
+ * is apparently a little-endian struct, including the args
+ *
+ * There is also some pervacious arg padding, so that args
+ * of a given length must begin at a boundary of that length
+ */
+
+ struct ieee80211_radiotap_header *rthdr =
+ (struct ieee80211_radiotap_header *) skb->data;
+
+ /* 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
+ */
+
+ static const u8 radiotap_entry_sizes[] = {
+ 8, /* IEEE80211_RADIOTAP_TSFT */
+ 1, /* IEEE80211_RADIOTAP_FLAGS */
+ 1, /* IEEE80211_RADIOTAP_RATE */
+ 4, /* IEEE80211_RADIOTAP_CHANNEL */
+ 2, /* IEEE80211_RADIOTAP_FHSS */
+ 1, /* IEEE80211_RADIOTAP_DBM_ANTSIGNAL */
+ 1, /* IEEE80211_RADIOTAP_DBM_ANTNOISE */
+ 2, /* IEEE80211_RADIOTAP_LOCK_QUALITY */
+ 2, /* IEEE80211_RADIOTAP_TX_ATTENUATION */
+ 2, /* IEEE80211_RADIOTAP_DB_TX_ATTENUATION */
+ 1, /* IEEE80211_RADIOTAP_DBM_TX_POWER */
+ 1, /* IEEE80211_RADIOTAP_ANTENNA */
+ 1, /* IEEE80211_RADIOTAP_DB_ANTSIGNAL */
+ 1 /* IEEE80211_RADIOTAP_DB_ANTNOISE */
+ /* add more here as they are defined */
+ };
+ int tap_index = 0;
+ u8 *tap_arg = skb->data + sizeof(struct ieee80211_radiotap_header);
+ u32 *curr_arg_bitmap = &rthdr->it_present;
+ u32 arg_bitmap = le32_to_cpu(*curr_arg_bitmap);
+
+ if (rthdr->it_version)
+ return TXRX_DROP; /* version byte as magic */
+
+ /* sanity check for skb length and radiotap length field */
+ if (skb->len < (le16_to_cpu(rthdr->it_len) +
+ sizeof(struct ieee80211_hdr)))
+ return TXRX_DROP;
+
+ /* find payload start allowing for extended bitmap(s) */
+
+ if (le32_to_cpu(rthdr->it_present) & 0x80000000) {
+ while (le32_to_cpu(*((u32 *)tap_arg)) & 0x80000000)
+ tap_arg += sizeof(u32);
+ tap_arg += sizeof(u32);
+ }
+
+ /* default control situation for all injected packets */
+
+ 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 we can at
+ * least skip (by knowing the length)...
+ */
+
+ while (tap_index < sizeof(radiotap_entry_sizes)) {
+ int i, target_rate;
+
+ if (!(arg_bitmap & 1))
+ goto next_entry;
+
+ /* 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
+ */
+
+ if (((int)tap_arg) & (radiotap_entry_sizes[tap_index]-1))
+ tap_arg += radiotap_entry_sizes[tap_index]-
+ (((int)tap_arg) &
+ (radiotap_entry_sizes[tap_index]-1));
+
+ /* see if this argument is something that interests us */
+
+ switch (tap_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 = (*tap_arg) * 5;
+ for (i = 0; i < tx->local->num_curr_rates; i++) {
+ struct ieee80211_rate *r =
+ &tx->local->curr_rates[i];
+
+ if (r->rate <= target_rate) {
+ 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 = tx->local->num_curr_rates;
+ }
+ }
+ break;
+
+ case IEEE80211_RADIOTAP_ANTENNA:
+ /* radiotap uses 0 for 1st ant,
+ * mac80211 is 1 for 1st ant
+ * absence of IEEE80211_RADIOTAP_ANTENNA
+ * gives default/diversity
+ */
+ control->antenna_sel_tx = (*tap_arg) + 1;
+ break;
+
+ case IEEE80211_RADIOTAP_DBM_TX_POWER:
+ control->power_level = *tap_arg;
+ break;
+
+ default:
+ break;
+ }
+
+ tap_arg += radiotap_entry_sizes[tap_index];
+
+ next_entry:
+
+ tap_index++;
+ if (unlikely((tap_index & 31) == 0)) {
+ /* completed current u32 bitmap */
+ if (arg_bitmap & 1) { /* b31 was set, there is more */
+ /* move to next u32 bitmap */
+ curr_arg_bitmap++;
+ arg_bitmap = le32_to_cpu(*curr_arg_bitmap);
+ } else {
+ /* no more bitmaps: end */
+ tap_index = sizeof(radiotap_entry_sizes);
+ }
+ } else { /* just try the next bit */
+ arg_bitmap >>= 1;
+ }
+ }
+
+ /* remove the radiotap header */
+ 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,
@@ -1062,6 +1235,9 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
{
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));
@@ -1071,7 +1247,32 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
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))
@@ -1088,9 +1289,6 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
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)];
@@ -1098,6 +1296,7 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
}
control->flags |= IEEE80211_TXCTL_FIRST_FRAGMENT;
+ return res;
}
static int inline is_ieee80211_device(struct net_device *dev,
@@ -1205,7 +1404,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
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));
@@ -1215,14 +1414,24 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
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;
- 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 */
@@ -1456,6 +1665,51 @@ static int ieee80211_subif_start_xmit(struct sk_buff *skb,
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)) {
+ /* radiotap version used as magic */
+ 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->mac.raw = skb->data+prthdr->it_len;
+ skb->nh.raw = skb->data+prthdr->it_len+
+ sizeof(struct ieee80211_hdr);
+ skb->h.raw = skb->data+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->nh.raw - skb->data;
h_pos = skb->h.raw - skb->data;
--
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 3/3] mac80211: Monitor mode radiotap injection docs
2007-03-19 11:01 [PATCH 0/3] Try #4: Radiotap on Monitor Mode interfaces for rx and tx andy
2007-03-19 11:01 ` [PATCH 1/3] mac80211: Add radiotap support andy
2007-03-19 11:01 ` [PATCH 2/3] mac80211: Monitor mode radiotap-based packet injection andy
@ 2007-03-19 11:01 ` andy
2 siblings, 0 replies; 6+ messages in thread
From: andy @ 2007-03-19 11:01 UTC (permalink / raw)
To: linux-wireless
From: Andy Green <andy@warmcat.com>
diff --git a/Documentation/networking/mac80211-injection.txt b/Documentation/networking/mac80211-injection.txt
new file mode 100644
index 0000000..bee8931
--- /dev/null
+++ b/Documentation/networking/mac80211-injection.txt
@@ -0,0 +1,77 @@
+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 ]
+
+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
+
+But note: all fields in the radiotap header are *little endian*.
+
+There is a fixed portion at the start which contains a u32 bitmap that defines
+if the possible argument is present or not. At the moment there are only 13
+possible arguments defined, but in case we run out of space in the u32 it is
+defined that b31 set indicates that there is another u32 bitmap following, and
+the start of the arguments is moved forward 4 bytes each time.
+
+After the fixed part of the header, the arguments follow.
+
+ - the arguments are all little-endian!
+
+ - 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.
+
+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>
--
^ permalink raw reply related [flat|nested] 6+ messages in thread