[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-Id: <200612181524.55838.flamingice@sourmilk.net>
Date: Mon, 18 Dec 2006 15:24:51 -0500
From: Michael Wu <flamingice@...rmilk.net>
To: Jiri Benc <jbenc@...e.cz>
Cc: David Kimdon <david.kimdon@...icescape.com>,
netdev@...r.kernel.org, John Linville <linville@...driver.com>
Subject: [PATCH] d80211: add radiotap support (v2)
d80211: add radiotap support
This patch adds support for radiotap to d80211. The driver must set
IEEE80211_HW_MONITOR_DURING_OPER as well as
IEEE80211_HW_RADIOTAP_SUPPORTED, and it must send radiotap frames when
there is at least one monitor interface up. Tested with zd1211rw-d80211.
Signed-off-by: Michael Wu <flamingice@...rmilk.net>
---
include/net/d80211.h | 3 +++
net/d80211/ieee80211.c | 41 ++++++++++++++++++++++++++++++++---------
net/d80211/ieee80211_iface.c | 5 ++++-
3 files changed, 39 insertions(+), 10 deletions(-)
diff --git a/include/net/d80211.h b/include/net/d80211.h
index 30980e1..27b2487 100644
--- a/include/net/d80211.h
+++ b/include/net/d80211.h
@@ -501,6 +501,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/d80211/ieee80211.c b/net/d80211/ieee80211.c
index 6e10db5..a73046c 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -8,6 +8,7 @@
*/
#include <net/d80211.h>
+#include <net/ieee80211_radiotap.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/netdevice.h>
@@ -284,6 +285,14 @@ int ieee80211_get_hdrlen_from_skb(struct
}
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_D80211_LOWTX_FRAME_DUMP
static void ieee80211_dump_frame(const char *ifname, const char *title,
struct sk_buff *skb)
@@ -2650,17 +2659,19 @@ ieee80211_rx_monitor(struct net_device *
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) < hlen) {
+ I802_DEBUG_INC(local->rx_expand_skb_head);
+ if (pskb_expand_head(skb, hlen, 0, GFP_ATOMIC)) {
+ dev_kfree_skb(skb);
+ return;
+ }
}
- }
- fi = (struct ieee80211_frame_info *) skb_push(skb, hlen);
+ fi = (struct ieee80211_frame_info *) skb_push(skb, hlen);
+ ieee80211_fill_frame_info(local, fi, status);
+ }
- ieee80211_fill_frame_info(local, fi, status);
sdata->stats.rx_packets++;
sdata->stats.rx_bytes += skb->len;
@@ -3064,6 +3075,10 @@ ieee80211_rx_h_monitor(struct ieee80211_
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;
}
@@ -3628,6 +3643,13 @@ void __ieee80211_rx(struct ieee80211_hw
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));
@@ -3664,6 +3686,7 @@ void __ieee80211_rx(struct ieee80211_hw
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;
@@ -3672,7 +3695,7 @@ void __ieee80211_rx(struct ieee80211_hw
} 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/d80211/ieee80211_iface.c b/net/d80211/ieee80211_iface.c
index 3e9d531..c1bb6d0 100644
--- a/net/d80211/ieee80211_iface.c
+++ b/net/d80211/ieee80211_iface.c
@@ -198,7 +198,10 @@ void ieee80211_if_set_type(struct net_de
break;
}
case IEEE80211_IF_TYPE_MNTR:
- dev->type = ARPHRD_IEEE80211_PRISM;
+ if (sdata->local->hw.flags & IEEE80211_HW_RADIOTAP_SUPPORTED)
+ dev->type = ARPHRD_IEEE80211_RADIOTAP;
+ else
+ dev->type = ARPHRD_IEEE80211_PRISM;
break;
default:
printk(KERN_WARNING "%s: %s: Unknown interface type 0x%x",
Content of type "application/pgp-signature" skipped
Powered by blists - more mailing lists