[PATCH] d80211: add radiotap support
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 <[EMAIL PROTECTED]> --- include/net/d80211.h |3 +++ net/d80211/ieee80211.c | 43 -- net/d80211/ieee80211_iface.c |5 - 3 files changed, 40 insertions(+), 11 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..c686f02 100644 --- a/net/d80211/ieee80211.c +++ b/net/d80211/ieee80211.c @@ -8,6 +8,7 @@ */ #include +#include #include #include #include @@ -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,24 +2659,26 @@ 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; skb->mac.raw = skb->data; skb->ip_summed = CHECKSUM_UNNECESSARY; skb->pkt_type = PACKET_OTHERHOST; - skb->protocol = htons(ETH_P_802_2); + skb->protocol = __constant_htons(ETH_P_802_2); memset(skb->cb, 0, sizeof(skb->cb)); netif_rx(skb); } @@ -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/ieee802
Re: [PATCH] d80211: add radiotap support
On Sat, Dec 16, 2006 at 06:01:03PM -0500, Michael Wu wrote: > skb->mac.raw = skb->data; > skb->ip_summed = CHECKSUM_UNNECESSARY; > skb->pkt_type = PACKET_OTHERHOST; > - skb->protocol = htons(ETH_P_802_2); > + skb->protocol = __constant_htons(ETH_P_802_2); > memset(skb->cb, 0, sizeof(skb->cb)); > netif_rx(skb); htons and friends can handle determining the argument is a constant on their own, so this change should be dropped. - To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] d80211: add radiotap support
On Monday 18 December 2006 12:20, David Kimdon wrote: > htons and friends can handle determining the argument is a constant on > their own, so this change should be dropped. > Hm, appears so. Didn't know that. I'll resend the patch without this change. Thanks, -Michael Wu pgpAgXQMS5hq0.pgp Description: PGP signature
Re: [PATCH] d80211: add radiotap support
On Sat, 16 Dec 2006 18:01:03 -0500, Michael Wu wrote: > 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. Shouldn't the stack create the radiotap header for the driver? Jiri -- Jiri Benc SUSE Labs - To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] d80211: add radiotap support
On Monday 18 December 2006 14:31, Jiri Benc wrote: > Shouldn't the stack create the radiotap header for the driver? > I will replace the current avs header generating code with basic (fixed len header) radiotap code too, but since radiotap is a variable length header, it is easier for the driver to fill it properly. Having drivers fill the radiotap header also avoids the problem of running out of header space. -Michael Wu pgpHliOi1pRSA.pgp Description: PGP signature
[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 <[EMAIL PROTECTED]> --- 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 +#include #include #include #include @@ -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) +